aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-07-07 13:22:53 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2025-11-11 00:08:15 +0100
commit7861a52adf92a083bb2aed4c35f98d8035dce032 (patch)
tree28cd3c40e4c878f730f5df3c1d93bdf91af490c3
parent7fc48e9216ff809da5f8055a50b0be17628ef1df (diff)
Setup project skeleton
-rw-r--r--.gitignore1
-rw-r--r--CMakeLists.txt29
-rw-r--r--README.md133
-rw-r--r--cmake/FindPSXSDK.cmake94
-rw-r--r--cmake/FindWASI_SDK.cmake39
-rw-r--r--cmake/ps1.cmake29
-rw-r--r--programs/CMakeLists.txt55
-rw-r--r--programs/initd/CMakeLists.txt31
-rw-r--r--programs/initd/initd.c30
-rw-r--r--programs/wasm-clang-toolchain.cmake37
-rw-r--r--programs/wnix/CMakeLists.txt26
-rw-r--r--programs/wnix/mkdir.c30
-rw-r--r--programs/wnix/mount.c32
-rw-r--r--programs/wnix/sbrk.c56
-rw-r--r--programs/wnix/start.c64
-rw-r--r--programs/yes/CMakeLists.txt31
-rw-r--r--programs/yes/yes.c34
-rw-r--r--res/CMakeLists.txt24
-rw-r--r--res/LICENSE6
-rw-r--r--res/font.bmpbin8206 -> 0 bytes
-rw-r--r--res/font_24.bmpbin48438 -> 0 bytes
-rw-r--r--res/functions.cmake4
-rw-r--r--res/orig/LICENSE5
-rw-r--r--res/orig/pixfont.pngbin0 -> 1962 bytes
-rw-r--r--res/orig/sprFont.pngbin5108 -> 0 bytes
-rw-r--r--res/pixfont.bmpbin0 -> 2450 bytes
-rw-r--r--res/pixfont_24.bmpbin0 -> 55350 bytes
-rw-r--r--src/CMakeLists.txt32
-rw-r--r--src/aio/CMakeLists.txt26
-rw-r--r--src/aio/include/aio.h40
-rw-r--r--src/aio/private_include/aio/types.h34
-rw-r--r--src/aio/src/CMakeLists.txt28
-rw-r--r--src/aio/src/close.c19
-rw-r--r--src/aio/src/free.c25
-rw-r--r--src/aio/src/mkdir.c137
-rw-r--r--src/aio/src/mount.c174
-rw-r--r--src/aio/src/open.c103
-rw-r--r--src/aio/src/poll.c77
-rw-r--r--src/aio/src/read.c82
-rw-r--r--src/aio/src/read_nb.c29
-rw-r--r--src/aio/src/stat.c117
-rw-r--r--src/aio/src/write.c82
-rw-r--r--src/bin/CMakeLists.txt35
-rw-r--r--src/bin/include/bin.h27
-rw-r--r--src/bin/private_include/bin/mod.h39
-rw-r--r--src/bin/private_include/bin/proc.h49
-rw-r--r--src/bin/private_include/bin/routines.h32
-rw-r--r--src/bin/private_include/bin/types.h99
-rw-r--r--src/bin/private_include/bin/wasi.h41
-rw-r--r--src/bin/private_include/bin/wasi/errno.h105
-rw-r--r--src/bin/private_include/bin/wnix.h37
-rw-r--r--src/bin/private_include/bin/wnix/routines.h29
-rw-r--r--src/bin/src/CMakeLists.txt30
-rw-r--r--src/bin/src/exec.c372
-rw-r--r--src/bin/src/globals.c21
-rw-r--r--src/bin/src/load.c28
-rw-r--r--src/bin/src/loaded.c32
-rw-r--r--src/bin/src/mod/CMakeLists.txt29
-rw-r--r--src/bin/src/mod/cfg.c106
-rw-r--r--src/bin/src/mod/eof.c28
-rw-r--r--src/bin/src/mod/free.c33
-rw-r--r--src/bin/src/mod/lock.c26
-rw-r--r--src/bin/src/mod/move.c62
-rw-r--r--src/bin/src/mod/pc.c29
-rw-r--r--src/bin/src/mod/read.c53
-rw-r--r--src/bin/src/mod/seek.c29
-rw-r--r--src/bin/src/mod/tell.c34
-rw-r--r--src/bin/src/mod/unload.c40
-rw-r--r--src/bin/src/mod/unlock.c27
-rw-r--r--src/bin/src/pid.c29
-rw-r--r--src/bin/src/proc/CMakeLists.txt33
-rw-r--r--src/bin/src/proc/cfg.c59
-rw-r--r--src/bin/src/proc/eof.c28
-rw-r--r--src/bin/src/proc/free.c40
-rw-r--r--src/bin/src/proc/global/CMakeLists.txt20
-rw-r--r--src/bin/src/proc/global/load.c39
-rw-r--r--src/bin/src/proc/global/store.c39
-rw-r--r--src/bin/src/proc/init.c38
-rw-r--r--src/bin/src/proc/linear/CMakeLists.txt20
-rw-r--r--src/bin/src/proc/linear/load.c40
-rw-r--r--src/bin/src/proc/linear/store.c40
-rw-r--r--src/bin/src/proc/lock.c27
-rw-r--r--src/bin/src/proc/move.c62
-rw-r--r--src/bin/src/proc/pc.c666
-rw-r--r--src/bin/src/proc/read.c51
-rw-r--r--src/bin/src/proc/seek.c29
-rw-r--r--src/bin/src/proc/stack/CMakeLists.txt23
-rw-r--r--src/bin/src/proc/stack/pop.c64
-rw-r--r--src/bin/src/proc/stack/ptr.c28
-rw-r--r--src/bin/src/proc/stack/push.c49
-rw-r--r--src/bin/src/proc/stack/read.c48
-rw-r--r--src/bin/src/proc/stack/write.c48
-rw-r--r--src/bin/src/proc/tell.c34
-rw-r--r--src/bin/src/proc/unlock.c27
-rw-r--r--src/bin/src/start.c127
-rw-r--r--src/bin/src/stop.c27
-rw-r--r--src/bin/src/update.c145
-rw-r--r--src/bin/src/wnix/CMakeLists.txt25
-rw-r--r--src/bin/src/wnix/argc.c33
-rw-r--r--src/bin/src/wnix/argcopy.c143
-rw-r--r--src/bin/src/wnix/arglen.c39
-rw-r--r--src/bin/src/wnix/exit.c37
-rw-r--r--src/bin/src/wnix/mkdir.c38
-rw-r--r--src/bin/src/wnix/mount.c298
-rw-r--r--src/bin/src/wnix/set_errno.c73
-rw-r--r--src/caio/CMakeLists.txt23
-rw-r--r--src/caio/include/caio.h43
-rw-r--r--src/caio/private_include/caio/routines.h27
-rw-r--r--src/caio/private_include/caio/types.h46
-rw-r--r--src/caio/src/CMakeLists.txt27
-rw-r--r--src/caio/src/cache.c38
-rw-r--r--src/caio/src/close.c44
-rw-r--r--src/caio/src/eof.c25
-rw-r--r--src/caio/src/open.c79
-rw-r--r--src/caio/src/read.c154
-rw-r--r--src/caio/src/readdebugmsg.c170
-rw-r--r--src/caio/src/readnodebug.c152
-rw-r--r--src/caio/src/seek.c35
-rw-r--r--src/caio/src/set_caches.c78
-rw-r--r--src/caio/src/tell.c26
-rw-r--r--src/caio/src/write.c29
-rw-r--r--src/drv/CMakeLists.txt28
-rw-r--r--src/drv/event/CMakeLists.txt18
-rw-r--r--src/drv/event/include/drv/event.h49
-rw-r--r--src/drv/include/drv/drv.h28
-rw-r--r--src/drv/include/drv/time.h28
-rw-r--r--src/drv/private_include/drv/port.h28
-rw-r--r--src/drv/private_include/drv/tree.h31
-rw-r--r--src/drv/private_include/drv/types.h30
-rw-r--r--src/drv/ps1/CMakeLists.txt37
-rw-r--r--src/drv/ps1/bios/CMakeLists.txt19
-rw-r--r--src/drv/ps1/bios/include/drv/ps1/bios.h128
-rw-r--r--src/drv/ps1/bios/src/CMakeLists.txt38
-rw-r--r--src/drv/ps1/bios/src/CdAsyncGetStatus.s21
-rw-r--r--src/drv/ps1/bios/src/CdAsyncReadSector.s21
-rw-r--r--src/drv/ps1/bios/src/CdAsyncSeekL.s21
-rw-r--r--src/drv/ps1/bios/src/CdInit.s21
-rw-r--r--src/drv/ps1/bios/src/CdRemove.s21
-rw-r--r--src/drv/ps1/bios/src/CloseEvent.s21
-rw-r--r--src/drv/ps1/bios/src/DisableEvent.s21
-rw-r--r--src/drv/ps1/bios/src/EnableEvent.s23
-rw-r--r--src/drv/ps1/bios/src/EnterCriticalSection.s25
-rw-r--r--src/drv/ps1/bios/src/ExitCriticalSection.s23
-rw-r--r--src/drv/ps1/bios/src/GetConf.s21
-rw-r--r--src/drv/ps1/bios/src/OpenEvent.s21
-rw-r--r--src/drv/ps1/bios/src/Printf.s21
-rw-r--r--src/drv/ps1/bios/src/RestoreState.s21
-rw-r--r--src/drv/ps1/bios/src/ReturnFromException.s21
-rw-r--r--src/drv/ps1/bios/src/SaveState.s21
-rw-r--r--src/drv/ps1/bios/src/SetConf.s21
-rw-r--r--src/drv/ps1/bios/src/SetCustomExitFromException.s21
-rw-r--r--src/drv/ps1/bios/src/TestEvent.s23
-rw-r--r--src/drv/ps1/bios/src/WaitEvent.s23
-rw-r--r--src/drv/ps1/cd/CMakeLists.txt27
-rw-r--r--src/drv/ps1/cd/include/drv/ps1/cd.h28
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h66
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h37
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/types.h111
-rw-r--r--src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h36
-rw-r--r--src/drv/ps1/cd/src/CMakeLists.txt33
-rw-r--r--src/drv/ps1/cd/src/ensure_event.c37
-rw-r--r--src/drv/ps1/cd/src/free.c23
-rw-r--r--src/drv/ps1/cd/src/getstat.c70
-rw-r--r--src/drv/ps1/cd/src/init.c42
-rw-r--r--src/drv/ps1/cd/src/next.c37
-rw-r--r--src/drv/ps1/cd/src/prv.c22
-rw-r--r--src/drv/ps1/cd/src/read.c239
-rw-r--r--src/drv/ps1/cd/src/readdebug253
-rw-r--r--src/drv/ps1/cd/src/send.c101
-rw-r--r--src/drv/ps1/cd/src/toseekl.c54
-rw-r--r--src/drv/ps1/cd/src/update.c47
-rw-r--r--src/drv/ps1/cd/src/virt/CMakeLists.txt25
-rw-r--r--src/drv/ps1/cd/src/virt/init.c41
-rw-r--r--src/drv/ps1/cd/src/write.c31
-rw-r--r--src/drv/ps1/cpu/CMakeLists.txt18
-rw-r--r--src/drv/ps1/cpu/include/drv/ps1/cpu.h24
-rw-r--r--src/drv/ps1/dma/CMakeLists.txt18
-rw-r--r--src/drv/ps1/dma/include/drv/ps1/dma.h97
-rw-r--r--src/drv/ps1/event/CMakeLists.txt20
-rw-r--r--src/drv/ps1/event/include/drv/ps1/event.h31
-rw-r--r--src/drv/ps1/event/src/CMakeLists.txt23
-rw-r--r--src/drv/ps1/event/src/close.c25
-rw-r--r--src/drv/ps1/event/src/disable.c25
-rw-r--r--src/drv/ps1/event/src/enable.c25
-rw-r--r--src/drv/ps1/event/src/open.c31
-rw-r--r--src/drv/ps1/event/src/test.c28
-rw-r--r--src/drv/ps1/gpu/CMakeLists.txt18
-rw-r--r--src/drv/ps1/gpu/include/drv/ps1/gpu.h173
-rw-r--r--src/drv/ps1/include/drv/ps1.h28
-rw-r--r--src/drv/ps1/irq/CMakeLists.txt20
-rw-r--r--src/drv/ps1/irq/include/drv/ps1/irq.h64
-rw-r--r--src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h24
-rw-r--r--src/drv/ps1/irq/private_include/drv/ps1/irq/types.h26
-rw-r--r--src/drv/ps1/irq/src/CMakeLists.txt22
-rw-r--r--src/drv/ps1/irq/src/handler.c32
-rw-r--r--src/drv/ps1/irq/src/head.c22
-rw-r--r--src/drv/ps1/irq/src/init.c40
-rw-r--r--src/drv/ps1/irq/src/set.c36
-rw-r--r--src/drv/ps1/mc/CMakeLists.txt20
-rw-r--r--src/drv/ps1/mc/include/drv/ps1/mc.h28
-rw-r--r--src/drv/ps1/mc/private_include/drv/ps1/mc/types.h37
-rw-r--r--src/drv/ps1/mc/src/CMakeLists.txt21
-rw-r--r--src/drv/ps1/mc/src/free.c23
-rw-r--r--src/drv/ps1/mc/src/init.c34
-rw-r--r--src/drv/ps1/mc/src/update.c26
-rw-r--r--src/drv/ps1/pad/CMakeLists.txt20
-rw-r--r--src/drv/ps1/pad/include/drv/ps1/pad.h28
-rw-r--r--src/drv/ps1/pad/private_include/drv/ps1/pad/types.h29
-rw-r--r--src/drv/ps1/pad/src/CMakeLists.txt21
-rw-r--r--src/drv/ps1/pad/src/free.c23
-rw-r--r--src/drv/ps1/pad/src/init.c34
-rw-r--r--src/drv/ps1/pad/src/update.c26
-rw-r--r--src/drv/ps1/private_include/drv/ps1/types.h35
-rw-r--r--src/drv/ps1/rcnt/CMakeLists.txt22
-rw-r--r--src/drv/ps1/rcnt/include/drv/ps1/rcnt.h45
-rw-r--r--src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h36
-rw-r--r--src/drv/ps1/rcnt/src/CMakeLists.txt19
-rw-r--r--src/drv/ps1/rcnt/src/init.c62
-rw-r--r--src/drv/ps1/sio/CMakeLists.txt22
-rw-r--r--src/drv/ps1/sio/include/drv/ps1/sio.h28
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h31
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h136
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h27
-rw-r--r--src/drv/ps1/sio/private_include/drv/ps1/sio/types.h65
-rw-r--r--src/drv/ps1/sio/src/CMakeLists.txt29
-rw-r--r--src/drv/ps1/sio/src/free.c23
-rw-r--r--src/drv/ps1/sio/src/globals.c21
-rw-r--r--src/drv/ps1/sio/src/init.c70
-rw-r--r--src/drv/ps1/sio/src/irq.c71
-rw-r--r--src/drv/ps1/sio/src/next.c34
-rw-r--r--src/drv/ps1/sio/src/read.c125
-rw-r--r--src/drv/ps1/sio/src/read_nb.c61
-rw-r--r--src/drv/ps1/sio/src/update.c98
-rw-r--r--src/drv/ps1/sio/src/write.c117
-rw-r--r--src/drv/ps1/src/CMakeLists.txt21
-rw-r--r--src/drv/ps1/src/free.c32
-rw-r--r--src/drv/ps1/src/init.c59
-rw-r--r--src/drv/ps1/src/update.c35
-rw-r--r--src/drv/ps1/time/CMakeLists.txt22
-rw-r--r--src/drv/ps1/time/include/drv/ps1/time.h24
-rw-r--r--src/drv/ps1/time/private_include/drv/ps1/time/types.h26
-rw-r--r--src/drv/ps1/time/src/CMakeLists.txt23
-rw-r--r--src/drv/ps1/time/src/getres.c34
-rw-r--r--src/drv/ps1/time/src/gettime.c38
-rw-r--r--src/drv/ps1/time/src/globals.c22
-rw-r--r--src/drv/ps1/time/src/settime.c37
-rw-r--r--src/drv/ps1/time/src/tick.c42
-rw-r--r--src/drv/src/CMakeLists.txt22
-rw-r--r--src/drv/src/free.c31
-rw-r--r--src/drv/src/init.c62
-rw-r--r--src/drv/src/tree.c51
-rw-r--r--src/drv/src/update.c32
-rw-r--r--src/drv/tty/CMakeLists.txt20
-rw-r--r--src/drv/tty/include/drv/tty.h28
-rw-r--r--src/drv/tty/private_include/drv/tty/font.h29
-rw-r--r--src/drv/tty/private_include/drv/tty/ops.h30
-rw-r--r--src/drv/tty/private_include/drv/tty/types.h40
-rw-r--r--src/drv/tty/src/CMakeLists.txt27
-rw-r--r--src/drv/tty/src/free.c39
-rw-r--r--src/drv/tty/src/init.c58
-rw-r--r--src/drv/tty/src/ps1/CMakeLists.txt19
-rw-r--r--src/drv/tty/src/ps1/ttyfont_tim.c801
-rw-r--r--src/drv/tty/src/setdim.c62
-rw-r--r--src/drv/tty/src/update.backup.c125
-rw-r--r--src/drv/tty/src/update.c126
-rw-r--r--src/drv/tty/src/write.c70
-rw-r--r--src/endian/CMakeLists.txt19
-rw-r--r--src/endian/include/endian.h46
-rw-r--r--src/endian/src/CMakeLists.txt24
-rw-r--r--src/endian/src/from_le16.c25
-rw-r--r--src/endian/src/from_le32.c26
-rw-r--r--src/endian/src/from_le64.c32
-rw-r--r--src/endian/src/to_le16.c32
-rw-r--r--src/endian/src/to_le32.c34
-rw-r--r--src/endian/src/to_le64.c38
-rw-r--r--src/fs/CMakeLists.txt24
-rw-r--r--src/fs/devfs/CMakeLists.txt20
-rw-r--r--src/fs/devfs/include/devfs.h24
-rw-r--r--src/fs/devfs/private_include/devfs/ops.h49
-rw-r--r--src/fs/devfs/private_include/devfs/types.h44
-rw-r--r--src/fs/devfs/src/CMakeLists.txt34
-rw-r--r--src/fs/devfs/src/close.c26
-rw-r--r--src/fs/devfs/src/flags.c25
-rw-r--r--src/fs/devfs/src/mkdir.c28
-rw-r--r--src/fs/devfs/src/mknod.c54
-rw-r--r--src/fs/devfs/src/mount.c59
-rw-r--r--src/fs/devfs/src/open.c57
-rw-r--r--src/fs/devfs/src/ops.c32
-rw-r--r--src/fs/devfs/src/read.c98
-rw-r--r--src/fs/devfs/src/read_nb.c41
-rw-r--r--src/fs/devfs/src/register.c44
-rw-r--r--src/fs/devfs/src/search.c29
-rw-r--r--src/fs/devfs/src/stat.c30
-rw-r--r--src/fs/devfs/src/status.c31
-rw-r--r--src/fs/devfs/src/unlink.c26
-rw-r--r--src/fs/devfs/src/update.c27
-rw-r--r--src/fs/devfs/src/write.c95
-rw-r--r--src/fs/include/fs/fs.h146
-rw-r--r--src/fs/include/fs/inode.h81
-rw-r--r--src/fs/iso9660/CMakeLists.txt20
-rw-r--r--src/fs/iso9660/include/iso9660.h24
-rw-r--r--src/fs/iso9660/private_include/iso9660/ops.h39
-rw-r--r--src/fs/iso9660/private_include/iso9660/routines.h35
-rw-r--r--src/fs/iso9660/private_include/iso9660/types.h148
-rw-r--r--src/fs/iso9660/src/CMakeLists.txt35
-rw-r--r--src/fs/iso9660/src/check_header.c39
-rw-r--r--src/fs/iso9660/src/close.c26
-rw-r--r--src/fs/iso9660/src/eof.c33
-rw-r--r--src/fs/iso9660/src/etotimespec.c40
-rw-r--r--src/fs/iso9660/src/gmtime.c35
-rw-r--r--src/fs/iso9660/src/lmsb16.c31
-rw-r--r--src/fs/iso9660/src/lmsb32.c31
-rw-r--r--src/fs/iso9660/src/mkdir.c28
-rw-r--r--src/fs/iso9660/src/mount.c180
-rw-r--r--src/fs/iso9660/src/open.c107
-rw-r--r--src/fs/iso9660/src/read.c27
-rw-r--r--src/fs/iso9660/src/register.c44
-rw-r--r--src/fs/iso9660/src/search.c557
-rw-r--r--src/fs/iso9660/src/stat.c28
-rw-r--r--src/fs/iso9660/src/totimespec.c54
-rw-r--r--src/fs/iso9660/src/totm.c72
-rw-r--r--src/fs/iso9660/src/write.c28
-rw-r--r--src/fs/private_include/fs/private.h63
-rw-r--r--src/fs/private_include/fs/types.h55
-rw-r--r--src/fs/ramfs/CMakeLists.txt20
-rw-r--r--src/fs/ramfs/include/ramfs.h43
-rw-r--r--src/fs/ramfs/private_include/ramfs/types.h31
-rw-r--r--src/fs/ramfs/src/CMakeLists.txt29
-rw-r--r--src/fs/ramfs/src/close.c25
-rw-r--r--src/fs/ramfs/src/flags.c25
-rw-r--r--src/fs/ramfs/src/free.c31
-rw-r--r--src/fs/ramfs/src/mkdir.c79
-rw-r--r--src/fs/ramfs/src/mknod.c87
-rw-r--r--src/fs/ramfs/src/mount.c69
-rw-r--r--src/fs/ramfs/src/open.c26
-rw-r--r--src/fs/ramfs/src/read.c26
-rw-r--r--src/fs/ramfs/src/search.c143
-rw-r--r--src/fs/ramfs/src/stat.c53
-rw-r--r--src/fs/ramfs/src/write.c26
-rw-r--r--src/fs/rootfs/CMakeLists.txt20
-rw-r--r--src/fs/rootfs/include/rootfs.h24
-rw-r--r--src/fs/rootfs/private_include/rootfs/ops.h42
-rw-r--r--src/fs/rootfs/private_include/rootfs/types.h32
-rw-r--r--src/fs/rootfs/src/CMakeLists.txt28
-rw-r--r--src/fs/rootfs/src/close.c25
-rw-r--r--src/fs/rootfs/src/flags.c26
-rw-r--r--src/fs/rootfs/src/mkdir.c30
-rw-r--r--src/fs/rootfs/src/mount.c42
-rw-r--r--src/fs/rootfs/src/open.c27
-rw-r--r--src/fs/rootfs/src/read.c26
-rw-r--r--src/fs/rootfs/src/register.c43
-rw-r--r--src/fs/rootfs/src/search.c29
-rw-r--r--src/fs/rootfs/src/stat.c28
-rw-r--r--src/fs/rootfs/src/write.c26
-rw-r--r--src/fs/src/CMakeLists.txt30
-rw-r--r--src/fs/src/from_type.c36
-rw-r--r--src/fs/src/headtail.c22
-rw-r--r--src/fs/src/inode/CMakeLists.txt20
-rw-r--r--src/fs/src/inode/free.c34
-rw-r--r--src/fs/src/inode/search.c121
-rw-r--r--src/fs/src/mountpoint.c60
-rw-r--r--src/fs/src/mp_from_path.c40
-rw-r--r--src/fs/src/mps_from_path.c89
-rw-r--r--src/fs/src/next.c62
-rw-r--r--src/fs/src/parent.c33
-rw-r--r--src/fs/src/register.c37
-rw-r--r--src/fs/src/relpath.c43
-rw-r--r--src/fs/src/update.c30
-rw-r--r--src/gfx/CMakeLists.txt25
-rw-r--r--src/gfx/include/gfx/gfx.h47
-rw-r--r--src/gfx/include/gfx/sprite.h32
-rw-r--r--src/gfx/ps1/CMakeLists.txt40
-rw-r--r--src/gfx/ps1/include/gfx/port.h126
-rw-r--r--src/gfx/ps1/private_include/gfx/private.h19
-rw-r--r--src/gfx/ps1/src/4line.c15
-rw-r--r--src/gfx/ps1/src/CMakeLists.txt33
-rw-r--r--src/gfx/ps1/src/deinit.c24
-rw-r--r--src/gfx/ps1/src/draw.c71
-rw-r--r--src/gfx/ps1/src/env.c71
-rw-r--r--src/gfx/ps1/src/heap.c74
-rw-r--r--src/gfx/ps1/src/init.c199
-rw-r--r--src/gfx/ps1/src/quad.c24
-rw-r--r--src/gfx/ps1/src/ready.c38
-rw-r--r--src/gfx/ps1/src/rect/CMakeLists.txt20
-rw-r--r--src/gfx/ps1/src/rect/init.c41
-rw-r--r--src/gfx/ps1/src/rect/sort.c27
-rw-r--r--src/gfx/ps1/src/sprite/CMakeLists.txt22
-rw-r--r--src/gfx/ps1/src/sprite/clone.c26
-rw-r--r--src/gfx/ps1/src/sprite/free.c23
-rw-r--r--src/gfx/ps1/src/sprite/load.c192
-rw-r--r--src/gfx/ps1/src/sprite/sort.c26
-rw-r--r--src/gfx/ps1/src/swapenvs.c58
-rw-r--r--src/gfx/ps1/src/vblank.c (renamed from src/libc/src/free.c)8
-rw-r--r--src/gfx/sdl-1.2/CMakeLists.txt19
-rw-r--r--src/gfx/sdl-1.2/include/gfx/port.h58
-rw-r--r--src/gfx/sdl-1.2/private_include/gfx/private.h26
-rw-r--r--src/gfx/sdl-1.2/src/CMakeLists.txt23
-rw-r--r--src/gfx/sdl-1.2/src/env.c204
-rw-r--r--src/gfx/sdl-1.2/src/line.c16
-rw-r--r--src/gfx/sdl-1.2/src/quad.c44
-rw-r--r--src/gfx/sdl-1.2/src/rect.c35
-rw-r--r--src/gfx/sdl-1.2/src/sprite.c143
-rw-r--r--src/gfx/src/CMakeLists.txt20
-rw-r--r--src/gfx/src/dim.c21
-rw-r--r--src/gfx/src/update.c27
-rw-r--r--src/init/CMakeLists.txt34
-rw-r--r--src/init/include/init.h28
-rw-r--r--src/init/private_include/init/port.h25
-rw-r--r--src/init/private_include/init/types.h37
-rw-r--r--src/init/ps1/CMakeLists.txt37
-rw-r--r--src/init/ps1/private_include/init/ps1/types.h40
-rw-r--r--src/init/ps1/src/CMakeLists.txt23
-rw-r--r--src/init/ps1/src/boot.c251
-rw-r--r--src/init/ps1/src/globalvars.c21
-rw-r--r--src/init/ps1/src/port.c30
-rw-r--r--src/init/ps1/src/run.c27
-rw-r--r--src/init/ps1/src/time.c47
-rw-r--r--src/init/src/CMakeLists.txt22
-rw-r--r--src/init/src/boot.c121
-rw-r--r--src/init/src/run.c27
-rw-r--r--src/init/src/vars.c21
-rw-r--r--src/init/src/vfs.c86
-rw-r--r--src/io/CMakeLists.txt20
-rw-r--r--src/io/include/io.h30
-rw-r--r--src/io/src/CMakeLists.txt6
-rw-r--r--src/io/src/mkdir.c40
-rw-r--r--src/io/src/mount.c35
-rw-r--r--src/io/src/open.c35
-rw-r--r--src/io/src/write.c35
-rw-r--r--src/kprintf/CMakeLists.txt20
-rw-r--r--src/kprintf/include/kprintf.h38
-rw-r--r--src/kprintf/src/CMakeLists.txt26
-rw-r--r--src/kprintf/src/kprintf.c34
-rw-r--r--src/kprintf/src/ktprintf.c35
-rw-r--r--src/kprintf/src/ktvprintf.c80
-rw-r--r--src/kprintf/src/kvprintf.c26
-rw-r--r--src/kprintf/src/nwp_log.c32
-rw-r--r--src/kprintf/src/wip_log.c44
-rw-r--r--src/libc/CMakeLists.txt25
-rw-r--r--src/libc/COPYING.NEWLIB1572
-rw-r--r--src/libc/include/ctype.h29
-rw-r--r--src/libc/include/errno.h136
-rw-r--r--src/libc/include/fcntl.h29
-rw-r--r--src/libc/include/inttypes.h34
-rw-r--r--src/libc/include/limits.h152
-rw-r--r--src/libc/include/setjmp.h29
-rw-r--r--src/libc/include/stdarg.h127
-rw-r--r--src/libc/include/stdbool.h54
-rw-r--r--src/libc/include/stddef.h451
-rw-r--r--src/libc/include/stdint.h33
-rw-r--r--src/libc/include/stdio.h16
-rw-r--r--src/libc/include/stdlib.h19
-rw-r--r--src/libc/include/string.h29
-rw-r--r--src/libc/include/sys/mount.h25
-rw-r--r--src/libc/include/sys/stat.h42
-rw-r--r--src/libc/include/sys/types.h26
-rw-r--r--src/libc/include/time.h46
-rw-r--r--src/libc/include/unistd.h26
-rw-r--r--src/libc/newlib/CMakeLists.txt18
-rw-r--r--src/libc/newlib/private_include/sys/_tz_structs.h30
-rw-r--r--src/libc/newlib/src/CMakeLists.txt18
-rw-r--r--src/libc/newlib/src/stdlib/CMakeLists.txt19
-rw-r--r--src/libc/newlib/src/stdlib/div.c121
-rw-r--r--src/libc/newlib/src/time/CMakeLists.txt25
-rw-r--r--src/libc/newlib/src/time/gettzinfo.c15
-rw-r--r--src/libc/newlib/src/time/local.h38
-rw-r--r--src/libc/newlib/src/time/mktime.c288
-rw-r--r--src/libc/newlib/src/time/month_lengths.c14
-rw-r--r--src/libc/newlib/src/time/tzcalc_limits.c76
-rw-r--r--src/libc/newlib/src/time/tzvars.c9
m---------src/libc/printf0
-rw-r--r--src/libc/private_include/libc/file.h11
-rw-r--r--src/libc/private_include/libc/malloc.h25
-rw-r--r--src/libc/src/CMakeLists.txt34
-rw-r--r--src/libc/src/ctype/CMakeLists.txt24
-rw-r--r--src/libc/src/ctype/isalpha.c24
-rw-r--r--src/libc/src/ctype/islower.c24
-rw-r--r--src/libc/src/ctype/isspace.c24
-rw-r--r--src/libc/src/ctype/isupper.c24
-rw-r--r--src/libc/src/ctype/tolower.c27
-rw-r--r--src/libc/src/ctype/toupper.c27
-rw-r--r--src/libc/src/errno.c18
-rw-r--r--src/libc/src/memcmp.c12
-rw-r--r--src/libc/src/memcpy.c13
-rw-r--r--src/libc/src/memset.c12
-rw-r--r--src/libc/src/ps1/CMakeLists.txt23
-rw-r--r--src/libc/src/ps1/putchar.c29
-rw-r--r--src/libc/src/ps1/setjmp.c25
-rw-r--r--src/libc/src/stdio/CMakeLists.txt19
-rw-r--r--src/libc/src/stdio/puts.c28
-rw-r--r--src/libc/src/stdlib/CMakeLists.txt30
-rw-r--r--src/libc/src/stdlib/abort.c25
-rw-r--r--src/libc/src/stdlib/abs.c (renamed from src/libc/src/malloc.c)7
-rw-r--r--src/libc/src/stdlib/calloc.c32
-rw-r--r--src/libc/src/stdlib/free.c29
-rw-r--r--src/libc/src/stdlib/labs.c24
-rw-r--r--src/libc/src/stdlib/llabs.c24
-rw-r--r--src/libc/src/stdlib/malloc.c42
-rw-r--r--src/libc/src/stdlib/realloc.c25
-rw-r--r--src/libc/src/stdlib/strtol.c31
-rw-r--r--src/libc/src/stdlib/strtoll.c91
-rw-r--r--src/libc/src/stdlib/strtoul.c31
-rw-r--r--src/libc/src/stdlib/strtoull.c85
-rw-r--r--src/libc/src/streams.c6
-rw-r--r--src/libc/src/strerror.c46
-rw-r--r--src/libc/src/string/CMakeLists.txt32
-rw-r--r--src/libc/src/string/memcmp.c30
-rw-r--r--src/libc/src/string/memcpy.c57
-rw-r--r--src/libc/src/string/memset.c46
-rw-r--r--src/libc/src/string/strcasecmp.c37
-rw-r--r--src/libc/src/string/strchr.c (renamed from src/libc/src/strchr.c)0
-rw-r--r--src/libc/src/string/strcmp.c27
-rw-r--r--src/libc/src/string/strcspn.c30
-rw-r--r--src/libc/src/string/strdup.c32
-rw-r--r--src/libc/src/string/strerror.c181
-rw-r--r--src/libc/src/string/strlen.c30
-rw-r--r--src/libc/src/string/strncmp.c29
-rw-r--r--src/libc/src/string/strndup.c32
-rw-r--r--src/libc/src/string/strpbrk.c36
-rw-r--r--src/libc/src/string/strrchr.c31
-rw-r--r--src/libc/src/string/strspn.c39
-rw-r--r--src/libc/src/strlen.c12
-rw-r--r--src/libc/src/ta_init.c21
-rw-r--r--src/libc/src/time/CMakeLists.txt21
-rw-r--r--src/libc/src/time/clock_getres.c25
-rw-r--r--src/libc/src/time/clock_gettime.c25
-rw-r--r--src/libc/src/time/clock_settime.c25
-rw-r--r--src/libc/src/unistd/CMakeLists.txt19
-rw-r--r--src/libc/src/unistd/sbrk.c38
m---------src/libc/tinyalloc0
-rw-r--r--src/loop/CMakeLists.txt20
-rw-r--r--src/loop/include/loop.h28
-rw-r--r--src/loop/private_include/loop/types.h26
-rw-r--r--src/loop/src/CMakeLists.txt22
-rw-r--r--src/loop/src/add_aio.c43
-rw-r--r--src/loop/src/globals.c21
-rw-r--r--src/loop/src/rm_aio.c48
-rw-r--r--src/loop/src/run.c39
-rw-r--r--src/main.c32
m---------src/nanowasm0
-rw-r--r--src/net/CMakeLists.txt20
-rw-r--r--src/net/include/net.h26
-rw-r--r--src/net/private_include/net/ops.h30
-rw-r--r--src/net/private_include/net/types.h39
-rw-r--r--src/net/src/CMakeLists.txt24
-rw-r--r--src/net/src/init.c78
-rw-r--r--src/net/src/net.c22
-rw-r--r--src/net/src/ops/CMakeLists.txt23
-rw-r--r--src/net/src/ops/alloc.c29
-rw-r--r--src/net/src/ops/free.c29
-rw-r--r--src/net/src/ops/read.c38
-rw-r--r--src/net/src/ops/realloc.c29
-rw-r--r--src/net/src/ops/write.c29
-rw-r--r--src/net/src/shutdown.c26
-rw-r--r--src/net/src/update.c31
-rw-r--r--src/page/CMakeLists.txt20
-rw-r--r--src/page/include/page.h31
-rw-r--r--src/page/private_include/page/mem.h27
-rw-r--r--src/page/private_include/page/mem/ops.h30
-rw-r--r--src/page/private_include/page/mem/types.h27
-rw-r--r--src/page/private_include/page/routines.h29
-rw-r--r--src/page/private_include/page/types.h42
-rw-r--r--src/page/src/CMakeLists.txt26
-rw-r--r--src/page/src/add.c39
-rw-r--r--src/page/src/free.c35
-rw-r--r--src/page/src/from_addr.c30
-rw-r--r--src/page/src/mem/CMakeLists.txt23
-rw-r--r--src/page/src/mem/alloc.c50
-rw-r--r--src/page/src/mem/free.c31
-rw-r--r--src/page/src/mem/ops.c27
-rw-r--r--src/page/src/mem/read.c34
-rw-r--r--src/page/src/mem/write.c34
-rw-r--r--src/page/src/read.c37
-rw-r--r--src/page/src/shrink.c36
-rw-r--r--src/page/src/write.c38
-rw-r--r--src/ps1/CMakeLists.txt32
-rw-r--r--src/ps1/playstation.x2
-rw-r--r--src/ps1/start.c2
-rw-r--r--src/ps1/system.cnf8
-rw-r--r--src/ps1/wnix.xml20
-rw-r--r--src/state/CMakeLists.txt18
-rw-r--r--src/state/include/state.h29
m---------src/wip0
-rw-r--r--tools/CMakeLists.txt37
-rwxr-xr-xtools/elf2exe.c250
m---------tools/nwc0
-rw-r--r--tools/tun2tcp/CMakeLists.txt21
-rw-r--r--tools/tun2tcp/README.md13
-rw-r--r--tools/tun2tcp/tun2tcp.c160
589 files changed, 28919 insertions, 362 deletions
diff --git a/.gitignore b/.gitignore
index a0155cb..7e8f746 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/build*/
+/src/ps1/*.dat
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9820c84..bb3c826 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-# wanix, a Unix-like operating system for WebAssembly
+# wnix, a Unix-like operating system for WebAssembly applications.
# Copyright (C) 2025 Xavier Del Campo Romero
#
# This program is free software: you can redistribute it and/or modify
@@ -21,16 +21,20 @@ set(TOOLS_PREFIX ${CMAKE_BINARY_DIR}/tools)
include(ExternalProject)
ExternalProject_Add(tools
SOURCE_DIR ${CMAKE_SOURCE_DIR}/tools
+ BUILD_ALWAYS ON
CMAKE_ARGS
+ -D CMAKE_EXPORT_COMPILE_COMMANDS=ON
-D CMAKE_INSTALL_PREFIX=${TOOLS_PREFIX})
-project(wanix C)
+project(wnix C ASM)
+option(WNIX_BUILD_PROGRAMS "Build userspace programs" ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
-add_compile_options(-mno-gpopt)
+add_compile_options(-mno-gpopt -ffunction-sections -fdata-sections)
if(CMAKE_TOOLCHAIN_FILE MATCHES "ps1")
set(PS1_BUILD 1)
+ option(WNIX_VIRT_CD "Virtualise CD driver through SIO")
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "win9x")
set(WIN9X_BUILD 1)
set(SDL1_2_BUILD 1)
@@ -40,7 +44,7 @@ else()
set(SDL1_2_BUILD 1)
endif()
-add_executable(${PROJECT_NAME} ${exec_flags} "src/main.c")
+add_executable(${PROJECT_NAME} ${exec_flags} src/main.c)
if(SDL1_2_BUILD)
find_package(SDL 1.2 REQUIRED)
@@ -58,16 +62,19 @@ if(NOT PS1_BUILD)
find_package(ENET 1.3 REQUIRED)
endif()
-set(cdroot ${CMAKE_BINARY_DIR}/cdimg)
-file(MAKE_DIRECTORY ${cdroot})
+set(cdroot ${CMAKE_BINARY_DIR})
if(PS1_BUILD)
- include("cmake/ps1.cmake")
+ include(cmake/ps1.cmake)
elseif(WIN9X_BUILD)
- include("cmake/win9x.cmake")
+ include(cmake/win9x.cmake)
elseif(HOST_BUILD)
- include("cmake/host.cmake")
+ include(cmake/host.cmake)
endif()
-add_subdirectory("res")
-add_subdirectory("src")
+add_subdirectory(res)
+add_subdirectory(src)
+
+if(WNIX_BUILD_PROGRAMS)
+ add_subdirectory(programs)
+endif()
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..fe66a7a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,133 @@
+# Wnix
+
+**DISCLAIMER: this project is in early stage development, and therefore**
+**not suitable for production environments.**
+
+Wnix (pronounced _woo-nix_ or _double u-nix_) is a small, Unix-like operating
+system aimed towards resource-constrained devices without a [MMU].
+Virtual memory semantics are instead achieved by *exclusively* running
+[WebAssembly] applications on its userspace, using the small and flexible
+interpreter [NanoWasm] as its backend.
+
+For the sake of simplicity, and as opposed to most operating systems,
+Wnix only requires one execution thread to perform all tasks. In other words,
+Wnix is highly concurrent, but not parallel, and relies entirely on
+co-operative execution of asynchronous (i.e., fast) tasks to achieve
+[concurrency].
+
+**Note:** while designed to remain portable, Wnix currently only targets the
+original [PlayStation].
+
+## Dependencies
+
+- A `mipsel-unknown-elf` cross-toolchain (i.e., GNU `binutils` and GCC).
+Here are [some notes](https://www.psxdev.net/forum/viewtopic.php?t=40)
+to build it from source.
+- `clang-18`
+- `libclang-18-dev`
+- Copy `libclang_rt.builtins-wasm32.a` (get from WASI-SDK) to
+`/usr/lib/llvm-18/lib/clang/18/lib`.
+- C and C++ compilers for the host platform.
+
+## How to build
+
+Configure with:
+
+```
+cmake -B build -DCMAKE_TOOLCHAIN_FILE=cmake/ps1-toolchain.cmake -DVIDEO_MODE=VMODE_PAL
+```
+
+Build with:
+
+```
+cmake --build build/ # Optionally, add -j$(nproc)
+```
+
+## FAQ
+
+### Why not a fully-fledged operating system like GNU/Linux or BSDs?
+
+While all these projects truly deserve uttermost respect, these are very
+complex projects that target a diverse range of highly sophisticated hardware.
+
+More specifically, regarding the original PlayStation there have been
+[several unsuccessful attempts](https://www.psxdev.net/forum/viewtopic.php?t=152&start=40)
+at running ancient versions of the Linux kernel (circa `2.4`), with
+[concerns](https://www.psxdev.net/forum/viewtopic.php?p=19405#p19405)
+about newer versions not being able to fit into the console's 2 MiB RAM.
+
+On the other hand, kernels like Linux are focused on running native
+executables (i.e., ELF files), where the semantics provided by MMUs would not
+be available on limited hardware like the original PlayStation.
+While it might still be possible to configure Linux to exclusively
+run WebAssembly applications somehow, Linux is still a very large and complex
+project that would require a big effort to port to a PlayStation.
+
+Since binary compatibility with existing Linux software is not a requirement,
+a simple operating system with Unix-like semantics is enough to allow
+WebAssembly applications to interact with the system via [WASI].
+
+Moreover, not having a MMU available would typically mean executables
+would be dumped to RAM before execution, with a non-negligible footprint.
+On the other hand, NanoWasm is designed to allow direct execution from any
+source, including read-only media like CD-ROMs.
+
+Similarly, NanoWasm allows to allocate and manipulate WebAssembly memories
+(linear memory, stack, etc.) from any source, including but not limited to
+memory cards or any other external mass storage, therefore allowing the system
+to outgrow its RAM size limitations, similarly to how fully-fledged operating
+systems like GNU/Linux implement virtual memory.
+
+More importantly, running userspace applications without a MMU would allow a
+malicious application to read/write memory from/to other processes, or even
+the kernel itself. Confining userspace applications into a sandbox can be
+achieved via WebAssembly, a bytecode representation that can be easily compiled
+down to from popular programming languages, such as C or C++, via [`wasi-sdk`].
+
+Of course, the design decisions above were made with memory efficiency and
+security in mind, at the cost of execution speed. Wnix is meant to provide
+similar tools compared to fully-fledged operating systems, at a fraction of
+their size.
+
+And last, but not least, Wnix was written as an attempt to learn about
+operating systems in general, and a way to have fun while implementing
+interesting ways to achieve virtual memory semantics and concurrency by
+software.
+
+## License
+
+```
+wnix, a Unix-like operating system for WebAssembly applications.
+Copyright (C) 2025 Xavier Del Campo Romero
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+```
+
+Wnix includes source code from other projects under various free software
+licenses. Unless explicitly noted otherwise, Wnix is licensed according to
+[`LICENSE`](LICENSE).
+
+## Disclaimer
+
+- Linux is a registered trademark of Linus Torvalds.
+- PlayStation is a registered trademark of its respective owners.
+- Unix is a registered trademark of its respective owners.
+
+[MMU]: https://en.wikipedia.org/wiki/Memory_management_unit
+[WebAssembly]: https://en.wikipedia.org/wiki/Webassembly
+[NanoWasm]: https://gitea.privatedns.org/xavi/nanowasm
+[PlayStation]: https://en.wikipedia.org/wiki/PlayStation_(console)
+[concurrency]: https://en.wikipedia.org/wiki/Concurrent_computing
+[WASI]: https://wasi.dev/
+[`wasi-sdk`]: https://github.com/WebAssembly/wasi-sdk
diff --git a/cmake/FindPSXSDK.cmake b/cmake/FindPSXSDK.cmake
deleted file mode 100644
index 2d1982d..0000000
--- a/cmake/FindPSXSDK.cmake
+++ /dev/null
@@ -1,94 +0,0 @@
-# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
-# file Copyright.txt or https://cmake.org/licensing for details.
-
-#[=======================================================================[.rst:
-FindPSXSDK
------------
-
-Find PSXSDK (an open source software development kit for the original
-Sony PlayStation) libraries and header files.
-
-Imported targets
-^^^^^^^^^^^^^^^^
-
-This module defines the following :prop_tgt:`IMPORTED` targets:
-
- ``PSXSDK::PSXSDK``,
- The PSXSDK `psx` library, if found.
-
-Result variables
-^^^^^^^^^^^^^^^^
-
-This module will set the following variables in your project:
-
-``PSXSDK_FOUND``
- true if PSXSDK libraries and header files were found.
-``PSXSDK_VERSION``
- PSXSDK release version
-``PSXSDK_INCLUDE_DIRS``
- the directory containing the PSXSDK headers; note
- ``PSXSDK_INCLUDE_DIRS`` is also required
-``PSXSDK_LIBRARIES``
- PSXSDK libraries to be linked; note ``PSXSDK_LIBRARIES`` is also
- required
-
-#]=======================================================================]
-
-find_path(PSXSDK_INCLUDE_DIRS
- NAMES
- huff.h
- meidogte.h
- meidogte_inline.h
- memcard.h
- modplay.h
- psxbios.h
- psxcdrom.h
- psxgpu.h
- psxgte.h
- psx.h
- psxpad.h
- psxsio.h
- psxspu.h
- psxutil.h
- runexe.h
- search.h
- HINTS
- ENV PSXSDK_PATH
- PATH_SUFFIXES
- include
-)
-
-find_library(PSXSDK_LIBRARIES
- NAMES psx
- HINTS
- ENV PSXSDK_PATH
- PATH_SUFFIXES
- lib
-)
-
-if(PSXSDK_INCLUDE_DIRS AND EXISTS "${PSXSDK_INCLUDE_DIRS}/psx.h")
- set(version_regex "^#define[ \t]+PSXSDK_VERSION_STRING[ \t]+\"([0-9\.]+)\"$")
- file(STRINGS "${PSXSDK_INCLUDE_DIRS}/psx.h" PSXSDK_VERSION_LINE REGEX ${version_regex})
- string(REGEX REPLACE ${version_regex} "\\1" PSXSDK_VERSION "${PSXSDK_VERSION_LINE}")
- unset(PSXSDK_VERSION_LINE)
- unset(version_regex)
-endif()
-
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(PSXSDK
- REQUIRED_VARS
- PSXSDK_LIBRARIES PSXSDK_INCLUDE_DIRS
- VERSION_VAR
- PSXSDK_VERSION
-)
-
-if(PSXSDK_FOUND)
- if(NOT TARGET PSXSDK::PSXSDK)
- add_library(PSXSDK::PSXSDK INTERFACE IMPORTED)
- target_include_directories(PSXSDK::PSXSDK
- INTERFACE "${PSXSDK_INCLUDE_DIRS}")
- set_target_properties(PSXSDK::PSXSDK PROPERTIES
- IMPORTED_LOCATION "${PSXSDK_LIBRARIES}")
- endif()
-endif()
diff --git a/cmake/FindWASI_SDK.cmake b/cmake/FindWASI_SDK.cmake
new file mode 100644
index 0000000..28c7993
--- /dev/null
+++ b/cmake/FindWASI_SDK.cmake
@@ -0,0 +1,39 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+find_program(WASI_SDK_CLANG
+ clang
+ PATHS
+ /opt/wasi-sdk/bin
+ ENV WASI_SDK_PATH
+ NO_DEFAULT_PATH
+)
+
+find_program(WASI_SDK_STRIP
+ strip
+ PATHS
+ /opt/wasi-sdk/bin
+ ENV WASI_SDK_PATH
+ NO_DEFAULT_PATH
+)
+
+include(FindPackageHandleStandardArgs)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(WASI_SDK
+ REQUIRED_VARS
+ WASI_SDK_CLANG
+ WASI_SDK_STRIP
+)
diff --git a/cmake/ps1.cmake b/cmake/ps1.cmake
index 21d77fa..14b6937 100644
--- a/cmake/ps1.cmake
+++ b/cmake/ps1.cmake
@@ -1,13 +1,8 @@
-find_package(PSXSDK 0.7.1 REQUIRED)
-
-target_compile_definitions(${PROJECT_NAME} PUBLIC FIXMATH_FAST_SIN PSXSDK_DEBUG)
-add_custom_target(exe ALL elf2exe ${PROJECT_NAME}
- ${cdroot}/${PROJECT_NAME}.exe -mark="A homebrew game created with PSXSDK"
+add_custom_target(exe ALL ${TOOLS_PREFIX}/bin/elf2exe ${PROJECT_NAME}
+ ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.exe
+ -mark="wnix, a Unix-like operating system for WebAssembly applications"
DEPENDS ${PROJECT_NAME})
-add_custom_target(iso ALL mkisofs -o ${PROJECT_NAME}.iso -V ${PROJECT_NAME}
- -sysid PLAYSTATION ${cdroot} DEPENDS exe)
-
-set(license_prefix $ENV{PSXSDK_PATH}/share/licenses)
+add_dependencies(exe tools)
if(VIDEO_MODE STREQUAL "VMODE_PAL")
set(region eur)
@@ -24,20 +19,16 @@ elseif(VIDEO_MODE STREQUAL "VMODE_NTSC")
set(region ${NTSC_REGION})
endif()
-set(license $ENV{PSXSDK_PATH}/share/licenses/info${region}.dat)
+add_custom_target(bin_cue ALL
+ ${TOOLS_PREFIX}/bin/mkpsxiso -q ${CMAKE_BINARY_DIR}/wnix.xml
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
-add_custom_target(bin_cue ALL mkpsxiso ${PROJECT_NAME}.iso ${PROJECT_NAME}.bin
- ${license} -s DEPENDS iso)
+add_dependencies(bin_cue exe tools)
-if(NOT EXISTS "${cdroot}/system.cnf")
- file(COPY "src/ps1/system.cnf" DESTINATION "${cdroot}")
-endif()
+set(cflags ${cflags})
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(cflags ${cflags} -Og)
else()
- set(cflags ${cflags} -Os)
+ set(cflags ${cflags} -O3 -g)
endif()
-
-set(cflags ${cflags} -fshort-enums)
-# libfixmath is already bundled with PSXSDK.
diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt
new file mode 100644
index 0000000..6d1cc25
--- /dev/null
+++ b/programs/CMakeLists.txt
@@ -0,0 +1,55 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set(programs
+ initd
+ yes
+)
+
+include(ExternalProject)
+find_package(Clang REQUIRED)
+file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+foreach(p ${programs})
+ set(cflags " \
+ -g \
+ ")
+
+ set(ldflags " \
+ ")
+
+ ExternalProject_Add(${p}_wnix
+ SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/${p}
+ BUILD_ALWAYS ON
+ CMAKE_ARGS
+ -D CMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_LIST_DIR}/wasm-clang-toolchain.cmake
+ -D CMAKE_C_FLAGS=${cflags}
+ -D CMAKE_EXE_LINKER_FLAGS=${ldflags}
+ -D CMAKE_BUILD_TYPE=Release
+ -D CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}
+ -D CMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}
+ )
+
+ add_custom_target(${p}_nwc ALL
+ ${TOOLS_PREFIX}/bin/nwc
+ ${CMAKE_CURRENT_BINARY_DIR}/bin/${p} ${CMAKE_BINARY_DIR}/bin/${p}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ BYPRODUCTS ${CMAKE_BINARY_DIR}/bin/${p}
+ )
+
+ add_dependencies(${p}_nwc ${p}_wnix tools)
+ add_dependencies(mkpsxiso_xml ${p}_nwc)
+endforeach()
diff --git a/programs/initd/CMakeLists.txt b/programs/initd/CMakeLists.txt
new file mode 100644
index 0000000..500782a
--- /dev/null
+++ b/programs/initd/CMakeLists.txt
@@ -0,0 +1,31 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+cmake_minimum_required(VERSION 3.13)
+include(GNUInstallDirs)
+project(initd C)
+add_executable(${PROJECT_NAME} initd.c)
+add_subdirectory(../wnix ${CMAKE_CURRENT_BINARY_DIR}/wnix)
+target_link_libraries(${PROJECT_NAME} PRIVATE wnix)
+# TODO: Debugging symbols could still be there, but nwc still has issues.
+add_custom_target(${PROJECT_NAME}_strip ALL
+ ${CMAKE_STRIP} ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+)
+add_dependencies(${PROJECT_NAME}_strip ${PROJECT_NAME})
+install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/programs/initd/initd.c b/programs/initd/initd.c
new file mode 100644
index 0000000..67ac4d4
--- /dev/null
+++ b/programs/initd/initd.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <sys/mount.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ if (mount("/dev/mc0", "/home", "ps1mcfs", 0, NULL))
+ return errno;
+
+ return 1;
+}
diff --git a/programs/wasm-clang-toolchain.cmake b/programs/wasm-clang-toolchain.cmake
new file mode 100644
index 0000000..450b0f9
--- /dev/null
+++ b/programs/wasm-clang-toolchain.cmake
@@ -0,0 +1,37 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+find_package(Clang REQUIRED)
+set(expr "^([0-9]+)\.([0-9]+)\.([0-9]+)$")
+string(REGEX REPLACE ${expr} "\\1" LLVM_VERSION_MAJOR "${LLVM_VERSION}")
+find_program(clang_exec clang-${LLVM_VERSION_MAJOR} REQUIRED)
+set(CMAKE_C_COMPILER ${clang_exec})
+set(CMAKE_C_COMPILER_WORKS 1)
+set(CMAKE_C_FLAGS " \
+ ${CMAKE_C_FLAGS} \
+ --target=wasm32-unknown-unknown-wasm \
+ -fno-exceptions \
+ -nostdinc \
+ -nostdlib \
+")
+set(CMAKE_EXE_LINKER_FLAGS "\
+ -Wl,--threads=1 \
+ --target=wasm32-unknown-unknown-wasm \
+ -fno-exceptions \
+ -nostdinc \
+ -nostdlib \
+")
+set(CMAKE_STRIP ${WASI_SDK_STRIP})
diff --git a/programs/wnix/CMakeLists.txt b/programs/wnix/CMakeLists.txt
new file mode 100644
index 0000000..a118bd0
--- /dev/null
+++ b/programs/wnix/CMakeLists.txt
@@ -0,0 +1,26 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(wnix
+ mkdir.c
+ mount.c
+ sbrk.c
+ start.c
+)
+set(LIBC_FREESTANDING ON)
+add_subdirectory(../../src/libc ${CMAKE_CURRENT_BINARY_DIR}/libc)
+target_compile_definitions(c PRIVATE PRINTF_DISABLE_SUPPORT_FLOAT)
+target_link_libraries(wnix PUBLIC c)
diff --git a/programs/wnix/mkdir.c b/programs/wnix/mkdir.c
new file mode 100644
index 0000000..5547616
--- /dev/null
+++ b/programs/wnix/mkdir.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+#include <errno.h>
+
+int mkdir(const char *const pathname, mode_t flags)
+{
+ int __wnix_mkdir(const char *, mode_t, int *) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("mkdir")
+ ));
+
+ return __wnix_mkdir(pathname, flags, &errno);
+}
diff --git a/programs/wnix/mount.c b/programs/wnix/mount.c
new file mode 100644
index 0000000..2512f73
--- /dev/null
+++ b/programs/wnix/mount.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <sys/mount.h>
+#include <errno.h>
+
+int mount(const char *const src, const char *const tgt, const char *const type,
+ const unsigned long flags, const void *const args)
+{
+ int __wnix_mount(const char *, const char *, const char *,
+ unsigned long, const void *, int *) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("mount")
+ ));
+
+ return __wnix_mount(src, tgt, type, flags, args, &errno);
+}
diff --git a/programs/wnix/sbrk.c b/programs/wnix/sbrk.c
new file mode 100644
index 0000000..7e32118
--- /dev/null
+++ b/programs/wnix/sbrk.c
@@ -0,0 +1,56 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+
+void *sbrk(const intptr_t increment)
+{
+ const unsigned pagesize = 64 << 10;
+ extern char __heap_base[];
+ static char *cur = __heap_base, *end;
+
+ if (increment < 0)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+ else if (!end)
+ end = cur + __builtin_wasm_memory_size(0) * pagesize;
+
+ if (increment >= (intptr_t)end || cur >= end - increment)
+ {
+ const unsigned long pages = (uintptr_t)increment / pagesize,
+ new_end = __builtin_wasm_memory_grow(0, pages);
+
+ if (!new_end)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ end = (void *)new_end;
+ }
+
+ void *ret = cur;
+
+ cur += increment;
+ return ret;
+}
diff --git a/programs/wnix/start.c b/programs/wnix/start.c
new file mode 100644
index 0000000..06dc4d5
--- /dev/null
+++ b/programs/wnix/start.c
@@ -0,0 +1,64 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void _start(void)
+{
+ int main(int, char *[]);
+ int __wnix_argc(void) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("argc")
+ ));
+ _Noreturn void __wnix_exit(int) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("exit")
+ ));
+
+ const int argc = __wnix_argc();
+ char **argv = malloc((argc + 1) * sizeof *argv);
+
+ if (!argv)
+ __wnix_exit(EXIT_FAILURE);
+
+ for (int i = 0; i < argc; i++)
+ {
+ size_t __wnix_arglen(int) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("arglen")
+ ));
+
+ int __wnix_argcopy(int, char *, int *) __attribute__((
+ __import_module__("wnix"),
+ __import_name__("argcopy")
+ ));
+
+ char *const arg = malloc(__wnix_arglen(i));
+
+ if (!arg)
+ __wnix_exit(EXIT_FAILURE);
+
+ __wnix_argcopy(i, arg, &errno);
+ argv[i] = arg;
+ }
+
+ argv[argc] = NULL;
+ __wnix_exit(main(argc, argv));
+}
diff --git a/programs/yes/CMakeLists.txt b/programs/yes/CMakeLists.txt
new file mode 100644
index 0000000..59abf8f
--- /dev/null
+++ b/programs/yes/CMakeLists.txt
@@ -0,0 +1,31 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+cmake_minimum_required(VERSION 3.13)
+include(GNUInstallDirs)
+project(yes C)
+add_executable(${PROJECT_NAME} yes.c)
+add_subdirectory(../wnix ${CMAKE_CURRENT_BINARY_DIR}/wnix)
+target_link_libraries(${PROJECT_NAME} PRIVATE wnix)
+# TODO: Debugging symbols could still be there, but nwc still has issues.
+add_custom_target(${PROJECT_NAME}_strip ALL
+ ${CMAKE_STRIP} ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+ BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}
+)
+add_dependencies(${PROJECT_NAME}_strip ${PROJECT_NAME})
+install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/programs/yes/yes.c b/programs/yes/yes.c
new file mode 100644
index 0000000..bdc9d9d
--- /dev/null
+++ b/programs/yes/yes.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if 0
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+#if 0
+ for (;;)
+ puts("y");
+
+ return EXIT_SUCCESS;
+#else
+return 0;
+#endif
+}
diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt
index 8fb119e..92baf7a 100644
--- a/res/CMakeLists.txt
+++ b/res/CMakeLists.txt
@@ -1,11 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
include(${CMAKE_CURRENT_LIST_DIR}/functions.cmake)
-sprite(NAME font
- X 472
+sprite(NAME pixfont
+ X 640
Y 0
BPP 4
- CX 368
+ CX 640
CY 498
TRANSPARENT TRUE)
-
-container(NAME ${PROJECT_NAME} SPRITES font)
diff --git a/res/LICENSE b/res/LICENSE
index 14474c2..0991335 100644
--- a/res/LICENSE
+++ b/res/LICENSE
@@ -1,6 +1,6 @@
All assets on this folder are either original or have originated from subfolder
"orig". Read LICENSE file in "orig" for further reference.
-font.bmp:
-font_24.bmp:
- Derived work from sprFont.png
+pixfont.bmp:
+pixfont_24.bmp:
+ Derived work from pixfont.png
diff --git a/res/font.bmp b/res/font.bmp
deleted file mode 100644
index 7fc1c36..0000000
--- a/res/font.bmp
+++ /dev/null
Binary files differ
diff --git a/res/font_24.bmp b/res/font_24.bmp
deleted file mode 100644
index b12a8ce..0000000
--- a/res/font_24.bmp
+++ /dev/null
Binary files differ
diff --git a/res/functions.cmake b/res/functions.cmake
index a0de87d..57119ce 100644
--- a/res/functions.cmake
+++ b/res/functions.cmake
@@ -20,7 +20,7 @@ function(sprite)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${SPRITE_NAME}.bmp
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${SPRITE_NAME})
- add_dependencies(iso ${SPRITE_NAME}_img)
+ add_dependencies(bin_cue ${SPRITE_NAME}_img)
elseif(SDL1_2_BUILD)
if(${SPRITE_TRANSPARENT})
set(trans "transparent=1")
@@ -57,7 +57,7 @@ function(sound)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${SOUND_NAME}.wav
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${SOUND_NAME})
- add_dependencies(iso ${SOUND_NAME}_snd)
+ add_dependencies(bin_cue ${SOUND_NAME}_snd)
elseif(SDL1_2_BUILD)
if(${SOUND_LOOP})
set(loop "loop=1")
diff --git a/res/orig/LICENSE b/res/orig/LICENSE
index bfab4ed..8860bc8 100644
--- a/res/orig/LICENSE
+++ b/res/orig/LICENSE
@@ -1,3 +1,4 @@
-sprFont.png:
- https://opengameart.org/content/kl-font
+pixfont.png:
+ https://opengameart.org/content/16x12-terminal-bitmap-font
+ Author: CruzR
License(s): CC0
diff --git a/res/orig/pixfont.png b/res/orig/pixfont.png
new file mode 100644
index 0000000..418b41d
--- /dev/null
+++ b/res/orig/pixfont.png
Binary files differ
diff --git a/res/orig/sprFont.png b/res/orig/sprFont.png
deleted file mode 100644
index 78a9d78..0000000
--- a/res/orig/sprFont.png
+++ /dev/null
Binary files differ
diff --git a/res/pixfont.bmp b/res/pixfont.bmp
new file mode 100644
index 0000000..addee36
--- /dev/null
+++ b/res/pixfont.bmp
Binary files differ
diff --git a/res/pixfont_24.bmp b/res/pixfont_24.bmp
new file mode 100644
index 0000000..e0682ee
--- /dev/null
+++ b/res/pixfont_24.bmp
Binary files differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0f28e58..05c73c4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,4 @@
-# wanix, a Unix-like operating system for WebAssembly
+# wnix, a Unix-like operating system for WebAssembly applications.
# Copyright (C) 2025 Xavier Del Campo Romero
#
# This program is free software: you can redistribute it and/or modify
@@ -14,17 +14,33 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
+set(NW_LOG_CUSTOM ON)
add_subdirectory(nanowasm)
-target_link_libraries(${PROJECT_NAME} PRIVATE nanowasm)
+set(WIP_LOG_CUSTOM ON)
+add_subdirectory(wip)
+add_subdirectory(dynstr)
# Avoid C11 since it is not supported by the i386-mingw32 toolchain.
-set(cflags ${cflags} -Wall -ffunction-sections -fdata-sections -pedantic)
+set(cflags ${cflags} -Wall -pedantic)
set(components
aio
+ bin
+ caio
+ drv
+ endian
+ fs
+ gfx
+ init
+ io
+ kprintf
+ loop
+ net
+ page
)
set(interfaces
+ state
)
if(PS1_BUILD)
@@ -35,24 +51,24 @@ endif()
target_compile_options(${PROJECT_NAME} PUBLIC ${cflags})
target_compile_options(nanowasm PUBLIC ${cflags})
# Dependencies for main.c
-# target_link_libraries(${PROJECT_NAME} PRIVATE)
+target_link_libraries(${PROJECT_NAME} PRIVATE gfx init loop)
foreach(c ${components})
- add_subdirectory("${c}")
+ add_subdirectory(${c})
target_compile_options(${c} PUBLIC ${cflags})
target_compile_features(${c} PUBLIC c_std_99)
set_target_properties(${c} PROPERTIES C_STANDARD 99 C_EXTENSIONS OFF)
target_link_libraries(${PROJECT_NAME} PRIVATE ${c})
if(PS1_BUILD)
- target_link_libraries(${c} PRIVATE c)
+ target_link_libraries(${c} PUBLIC c)
endif()
endforeach()
foreach(i ${interfaces})
- add_subdirectory("${i}")
+ add_subdirectory(${i})
target_compile_options(${i} INTERFACE ${cflags})
- target_link_libraries(${PROJECT_NAME} PRIVATE ${c})
+ target_link_libraries(${i} INTERFACE ${c})
endforeach()
target_link_options(${PROJECT_NAME} PRIVATE -Wl,--gc-sections)
diff --git a/src/aio/CMakeLists.txt b/src/aio/CMakeLists.txt
index 3f4561a..278192b 100644
--- a/src/aio/CMakeLists.txt
+++ b/src/aio/CMakeLists.txt
@@ -1,6 +1,20 @@
-set(src
- "src/close.c"
- "src/open.c"
-)
-add_library(aio ${src})
-target_include_directories(aio PUBLIC "include" PRIVATE "private_include")
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(aio)
+add_subdirectory(src)
+target_include_directories(aio PUBLIC include PRIVATE private_include)
+target_link_libraries(aio PUBLIC fs INTERFACE state)
diff --git a/src/aio/include/aio.h b/src/aio/include/aio.h
index f9f76cb..9486f3f 100644
--- a/src/aio/include/aio.h
+++ b/src/aio/include/aio.h
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -19,17 +19,41 @@
#ifndef AIO_H
#define AIO_H
+#include <fs/fs.h>
+#include <sys/types.h>
+#include <state.h>
+#include <stdbool.h>
#include <stddef.h>
-enum
+struct aio_poll
{
- AIO_POLLIN = 1,
- AIO_POLLOUT = 1 << 1
+ const struct aio *aio;
+ bool done;
+ int error;
+ struct aio_poll *prev, *next;
};
-struct aio *aio_open(const char *path, const char *mode);
-int aio_poll(struct aio **io, size_t n);
-int aio_event(const struct aio *io, int ev);
-int aio_close(struct aio *io);
+struct aio_done
+{
+ int (*f)(enum state state, void *args);
+ void *args;
+};
+
+struct aio_mount
+{
+ struct fs_mount mount;
+ const char *type;
+};
+
+struct aio *aio_mount(const struct aio_mount *m, const struct aio_done *d);
+struct aio *aio_mkdir(const struct fs_mkdir *m, const struct aio_done *d);
+struct aio *aio_open(const struct fs_open *o, const struct aio_done *d);
+struct aio *aio_read(const struct fs_read *r, const struct aio_done *d);
+struct aio *aio_write(const struct fs_write *w, const struct aio_done *d);
+struct aio *aio_stat(const struct fs_stat *s, const struct aio_done *d);
+int aio_read_nb(const struct fs_read *r);
+int aio_poll(struct aio_poll *p, int ms);
+int aio_close(struct fs_fd *fd);
+void aio_free(struct aio *io);
#endif
diff --git a/src/aio/private_include/aio/types.h b/src/aio/private_include/aio/types.h
index 31ee414..1fee8c1 100644
--- a/src/aio/private_include/aio/types.h
+++ b/src/aio/private_include/aio/types.h
@@ -1,16 +1,32 @@
-#ifndef AIO_PRV_OPEN_H
-#define AIO_PRV_OPEN_H
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
-enum aio_state
-{
- AIO_OK,
- AIO_AGAIN,
- AIO_FATAL
-};
+#ifndef AIO_TYPES_H
+#define AIO_TYPES_H
+
+#include <aio.h>
+#include <fs/fs.h>
struct aio
{
- enum aio_state (*next)(struct aio *);
+ int error;
+ struct fs_ret r;
+ struct aio_done done;
};
#endif
diff --git a/src/aio/src/CMakeLists.txt b/src/aio/src/CMakeLists.txt
new file mode 100644
index 0000000..ba4af9c
--- /dev/null
+++ b/src/aio/src/CMakeLists.txt
@@ -0,0 +1,28 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(aio PRIVATE
+ close.c
+ free.c
+ mkdir.c
+ mount.c
+ open.c
+ poll.c
+ read.c
+ read_nb.c
+ stat.c
+ write.c
+)
diff --git a/src/aio/src/close.c b/src/aio/src/close.c
index a6067a8..68c5dd7 100644
--- a/src/aio/src/close.c
+++ b/src/aio/src/close.c
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -17,18 +17,13 @@
*/
#include <aio.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <aio/types.h>
+#include <fs/fs.h>
-int aio_close(struct aio *const aio)
+int aio_close(struct fs_fd *const fd)
{
- if (!aio)
- {
- errno = EINVAL;
- return EOF;
- }
+ if (fd->mp && fd->mp->fs)
+ return fd->mp->fs->close(fd);
- free(aio);
- return 0;
+ return -1;
}
diff --git a/src/aio/src/free.c b/src/aio/src/free.c
new file mode 100644
index 0000000..cfefb1c
--- /dev/null
+++ b/src/aio/src/free.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <stdlib.h>
+
+void aio_free(struct aio *const aio)
+{
+ free(aio);
+}
diff --git a/src/aio/src/mkdir.c b/src/aio/src/mkdir.c
new file mode 100644
index 0000000..40b09b6
--- /dev/null
+++ b/src/aio/src/mkdir.c
@@ -0,0 +1,137 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct mkdir
+{
+ struct fs_mkdir mkdir;
+ struct aio_done done;
+ char *path, *parent;
+ struct aio *aio;
+};
+
+static void free_mkdir(struct mkdir *const mk)
+{
+ if (mk)
+ {
+ free(mk->path);
+ free(mk->parent);
+ }
+
+ free(mk);
+}
+
+static int done(const enum state state, void *const args)
+{
+ int ret = 0;
+ struct mkdir *const mk = args;
+ const struct aio_done *const d = &mk->done;
+
+ if (d->f)
+ ret = d->f(state, d->args);
+
+ free_mkdir(mk);
+ return ret;
+}
+
+static int search_done(const enum state state,
+ const char *const relpath, const struct fs_mp *const mp,
+ const union inode_result *const inode, void *const args)
+{
+ struct mkdir *const mk = args;
+ struct aio *const aio = mk->aio;
+ const struct fs *const fs = mp->fs;
+ const char *path = mk->path;
+ struct fs_ret r;
+
+ path += strlen(mp->tgt) + strlen(relpath);
+ mk->mkdir.path = path;
+
+ if (fs->mkdir(&mk->mkdir, mp, inode, &r))
+ goto failure;
+
+ aio->r = r;
+ return 0;
+
+failure:
+ aio->error = errno;
+ aio->done = mk->done;
+ free_mkdir(mk);
+ return -1;
+}
+
+struct aio *aio_mkdir(const struct fs_mkdir *const m,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct mkdir *mk = NULL;
+ char *const pathdup = strdup(m->path), *parent = NULL;
+
+ if (!pathdup
+ || !(parent = fs_parent(m->path))
+ || !(mk = malloc(sizeof *mk))
+ || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ *mk = (const struct mkdir)
+ {
+ .path = pathdup,
+ .parent = parent,
+ .aio = aio,
+ .mkdir = *m
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .args = mk,
+ .f = done
+ }
+ };
+
+ const struct inode_search s =
+ {
+ .path = parent,
+ .done = search_done,
+ .args = mk
+ };
+
+ if (d)
+ mk->done = *d;
+ else if (inode_search(&s, &aio->r))
+ goto failure;
+
+ return aio;
+
+failure:
+ free(mk);
+ free(aio);
+ free(parent);
+ free(pathdup);
+ return NULL;
+}
diff --git a/src/aio/src/mount.c b/src/aio/src/mount.c
new file mode 100644
index 0000000..418fb69
--- /dev/null
+++ b/src/aio/src/mount.c
@@ -0,0 +1,174 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct mount
+{
+ char *src, *tgt;
+ struct aio *aio;
+ const struct fs *fs;
+ struct fs_mount mount;
+ struct aio_done done;
+};
+
+static void free_mount(struct mount *const m)
+{
+ if (m)
+ {
+ free(m->src);
+ free(m->tgt);
+ }
+
+ free(m);
+}
+
+static int done(const enum state state, void *const args)
+{
+ int ret = 0;
+ struct mount *const m = args;
+ const struct aio_done *const d = &m->done;
+
+ if (d->f)
+ ret = d->f(state, d->args);
+
+ free_mount(m);
+ return ret;
+}
+
+static int search_done(const enum state s, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct mount *const m = args;
+ struct aio *const aio = m->aio;
+ const struct fs *const fs = m->fs;
+
+ if (strcmp(m->tgt, "/"))
+ {
+ if (!inode)
+ {
+ aio->error = ENOENT;
+ goto failure;
+ }
+ else if (mp->fs->iops.flags(inode) & INODE_MOUNTPOINT)
+ {
+ aio->error = EBUSY;
+ goto failure;
+ }
+ }
+
+ if (fs->mount(&m->mount, &aio->r))
+ {
+ aio->error = errno;
+ goto failure;
+ }
+
+ return 0;
+
+failure:
+ aio->done = m->done;
+ free_mount(m);
+ return -1;
+}
+
+struct aio *aio_mount(const struct aio_mount *const am,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ const struct fs_mount *const m = &am->mount;
+ const struct fs *const fs = fs_from_type(am->type);
+ char *srcdup = NULL, *tgtdup = NULL;
+ struct mount *pm = NULL;
+ struct fs_mp mp;
+
+ if (!fs)
+ {
+ errno = ENODEV;
+ goto failure;
+ }
+ else if (!m->src && fs->flags & FS_DEV_REQUIRED)
+ {
+ errno = ENOTBLK;
+ goto failure;
+ }
+ else if (!fs_mp_from_path(m->tgt, &mp)
+ && m->src && !strcmp(mp.src, m->src))
+ {
+ errno = EBUSY;
+ goto failure;
+ }
+ else if ((m->src && !(srcdup = strdup(m->src)))
+ || !(tgtdup = strdup(m->tgt))
+ || !(pm = malloc(sizeof *pm))
+ || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ const struct inode_search s =
+ {
+ .path = m->tgt,
+ .done = search_done,
+ .args = pm
+ };
+
+ *pm = (const struct mount)
+ {
+ .aio = aio,
+ .src = srcdup,
+ .tgt = tgtdup,
+ .fs = fs,
+ .mount =
+ {
+ .src = srcdup,
+ .tgt = tgtdup,
+ .mode = m->mode,
+ .gid = m->gid,
+ .uid = m->uid
+ }
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .f = done,
+ .args = pm
+ }
+ };
+
+ if (inode_search(&s, &aio->r))
+ goto failure;
+ else if (d)
+ pm->done = *d;
+
+ return aio;
+
+failure:
+ free(tgtdup);
+ free(srcdup);
+ free(pm);
+ free(aio);
+ return NULL;
+}
diff --git a/src/aio/src/open.c b/src/aio/src/open.c
index 89fbbba..4ee94a9 100644
--- a/src/aio/src/open.c
+++ b/src/aio/src/open.c
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -16,18 +16,111 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+#include <aio.h>
+#include <fs/fs.h>
#include <aio/types.h>
+#include <state.h>
+#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
-struct aio *aio_open(const char *const path, const char *const mode)
+struct open
{
- struct aio *const ret = malloc(sizeof *ret);
+ struct aio *aio;
+ struct fs_open open;
+ struct aio_done done;
+};
- if (!ret)
+static int done(const enum state s, void *const args)
+{
+ struct open *const o = args;
+ const struct aio_done *const d = &o->done;
+
+ if (d->f)
+ d->f(s, d->args);
+
+ free(o);
+ return 0;
+}
+
+static enum state opened(void *const args)
+{
+ return STATE_OK;
+}
+
+static int search_done(const enum state state, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct open *const o = args;
+ struct aio *const aio = o->aio;
+ const struct fs *const fs = mp->fs;
+
+ if (!inode)
+ {
+ aio->error = ENOENT;
goto failure;
+ }
+
+ aio->r = (const struct fs_ret)
+ {
+ .f = opened,
+ .args = o
+ };
+
+ if (fs->open(&o->open, mp, inode, &aio->r))
+ {
+ aio->error = errno;
+ goto failure;
+ }
+
+ return 0;
+
+failure:
+ aio->done = o->done;
+ free(o);
+ return -1;
+}
+
+struct aio *aio_open(const struct fs_open *const op,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct open *const o = malloc(sizeof *o);
+
+ if (!o || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ *o = (const struct open)
+ {
+ .aio = aio,
+ .open = *op
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .f = done,
+ .args = o
+ }
+ };
+
+ const struct inode_search s =
+ {
+ .path = op->path,
+ .done = search_done,
+ .args = o
+ };
+
+ if (inode_search(&s, &aio->r))
+ goto failure;
+ else if (d)
+ o->done = *d;
+
+ return aio;
failure:
- free(ret);
+ free(aio);
return NULL;
}
diff --git a/src/aio/src/poll.c b/src/aio/src/poll.c
new file mode 100644
index 0000000..9a792a8
--- /dev/null
+++ b/src/aio/src/poll.c
@@ -0,0 +1,77 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <state.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <time.h>
+
+int aio_poll(struct aio_poll *const poll, int ms)
+{
+ struct timespec init;
+
+ if (ms > 0 && clock_gettime(CLOCK_REALTIME, &init))
+ return -1;
+
+ do
+ {
+ for (struct aio_poll *p = poll; p;)
+ {
+ struct aio_poll *const next = p->next;
+ const struct aio *const aio = p->aio;
+ const struct fs_ret *const r = &aio->r;
+ const enum state s = r->f(r->args);
+
+ switch (s)
+ {
+ case STATE_AGAIN:
+ break;
+
+ case STATE_FATAL:
+ p->error = aio->error;
+ /* Fall through */
+ case STATE_OK:
+ {
+ const struct aio_done *const d = &aio->done;
+
+ if (d->f)
+ return d->f(s, d->args) ? -1 : 1;
+
+ p->done = true;
+ return 1;
+ }
+ }
+
+ p = next;
+ }
+
+ if (ms > 0)
+ {
+ struct timespec after;
+
+ if (clock_gettime(CLOCK_REALTIME, &after))
+ return -1;
+
+ /* TODO */
+ }
+ } while (ms);
+
+ return 0;
+}
diff --git a/src/aio/src/read.c b/src/aio/src/read.c
new file mode 100644
index 0000000..f57c3b0
--- /dev/null
+++ b/src/aio/src/read.c
@@ -0,0 +1,82 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <fs/fs.h>
+#include <aio/types.h>
+#include <state.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct read
+{
+ struct aio_done done;
+};
+
+static int done(const enum state s, void *const args)
+{
+ int ret = 0;
+ struct read *const r = args;
+ const struct aio_done *const d = &r->done;
+
+ if (d->f)
+ ret = d->f(s, d->args);
+
+ free(r);
+ return ret;
+}
+
+static enum state read_done(void *const args)
+{
+ return STATE_OK;
+}
+
+struct aio *aio_read(const struct fs_read *const fr,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct read *const r = malloc(sizeof *r);
+ struct fs_fd *const fd = fr->fd;
+ const struct fs *const fs = fd->mp->fs;
+
+ if (!r || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ *r = (const struct read){0};
+ *aio = (const struct aio)
+ {
+ .r.f = read_done,
+ .done =
+ {
+ .f = done,
+ .args = r
+ }
+ };
+
+ if (fs->read(fr, &aio->r))
+ goto failure;
+ else if (d)
+ r->done = *d;
+
+ return aio;
+
+failure:
+ free(r);
+ free(aio);
+ return NULL;
+}
diff --git a/src/aio/src/read_nb.c b/src/aio/src/read_nb.c
new file mode 100644
index 0000000..133a75a
--- /dev/null
+++ b/src/aio/src/read_nb.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <fs/fs.h>
+
+int aio_read_nb(const struct fs_read *const fr)
+{
+ const struct fs_fd *const fd = fr->fd;
+ const struct fs *const fs = fd->mp->fs;
+
+ return fs->read_nb(fr);
+}
diff --git a/src/aio/src/stat.c b/src/aio/src/stat.c
new file mode 100644
index 0000000..4c8ae35
--- /dev/null
+++ b/src/aio/src/stat.c
@@ -0,0 +1,117 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <aio/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct stat_prv
+{
+ struct fs_stat stat;
+ struct aio_done done;
+ struct aio *aio;
+};
+
+static int done(const enum state state, void *const args)
+{
+ int ret = 0;
+ struct stat_prv *const p = args;
+ const struct aio_done *const d = &p->done;
+
+ if (d->f)
+ ret = d->f(state, d->args);
+
+ free(p);
+ return ret;
+}
+
+static int search_done(const enum state s, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct stat_prv *const p = args;
+ struct aio *const aio = p->aio;
+ const struct fs *const fs = mp->fs;
+
+ if (!inode)
+ {
+ aio->error = ENOENT;
+ goto failure;
+ }
+ else if (fs->stat(&p->stat, mp, inode, &aio->r))
+ {
+ aio->error = errno;
+ goto failure;
+ }
+
+ return 0;
+
+failure:
+ aio->done = p->done;
+ free(p);
+ return -1;
+}
+
+struct aio *aio_stat(const struct fs_stat *const as,
+ const struct aio_done *const d)
+{
+ struct aio *const aio = malloc(sizeof *aio);
+ struct stat_prv *const p = malloc(sizeof *p);
+
+ if (!p || !aio)
+ goto failure;
+
+ const struct inode_search s =
+ {
+ .path = as->path,
+ .done = search_done,
+ .args = p
+ };
+
+ *p = (const struct stat_prv)
+ {
+ .aio = aio,
+ .stat = *as
+ };
+
+ *aio = (const struct aio)
+ {
+ .done =
+ {
+ .f = done,
+ .args = p
+ }
+ };
+
+ if (inode_search(&s, &aio->r))
+ goto failure;
+ else if (d)
+ p->done = *d;
+
+ return aio;
+
+failure:
+ free(p);
+ free(aio);
+ return NULL;
+}
diff --git a/src/aio/src/write.c b/src/aio/src/write.c
new file mode 100644
index 0000000..75f167f
--- /dev/null
+++ b/src/aio/src/write.c
@@ -0,0 +1,82 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <aio.h>
+#include <fs/fs.h>
+#include <aio/types.h>
+#include <state.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct write
+{
+ struct aio_done done;
+};
+
+static int done(const enum state s, void *const args)
+{
+ int ret = 0;
+ struct write *const w = args;
+ const struct aio_done *const d = &w->done;
+
+ if (d->f)
+ ret = d->f(s, d->args);
+
+ free(w);
+ return ret;
+}
+
+static enum state write_done(void *const args)
+{
+ return STATE_OK;
+}
+
+struct aio *aio_write(const struct fs_write *const fw,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct write *const w = malloc(sizeof *w);
+ struct fs_fd *const fd = fw->fd;
+ const struct fs *const fs = fd->mp->fs;
+
+ if (!w || !(aio = malloc(sizeof *aio)))
+ goto failure;
+
+ *w = (const struct write){0};
+ *aio = (const struct aio)
+ {
+ .r.f = write_done,
+ .done =
+ {
+ .f = done,
+ .args = w
+ }
+ };
+
+ if (fs->write(fw, &aio->r))
+ goto failure;
+ else if (d)
+ w->done = *d;
+
+ return aio;
+
+failure:
+ free(w);
+ free(aio);
+ return NULL;
+}
diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt
new file mode 100644
index 0000000..c0031b3
--- /dev/null
+++ b/src/bin/CMakeLists.txt
@@ -0,0 +1,35 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(bin)
+add_subdirectory(src)
+target_include_directories(bin PUBLIC include PRIVATE private_include)
+target_link_libraries(bin PRIVATE
+ aio
+ caio
+ dynstr
+ endian
+ fs
+ kprintf
+ loop
+ nanowasm
+ page
+ state
+
+
+
+ drv_ps1_bios
+)
diff --git a/src/bin/include/bin.h b/src/bin/include/bin.h
new file mode 100644
index 0000000..a5528c5
--- /dev/null
+++ b/src/bin/include/bin.h
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_H
+#define BIN_H
+
+#include <sys/types.h>
+
+int bin_exec(const char *path, const char *const *argv, uid_t uid, gid_t gid);
+int bin_update(void);
+
+#endif
diff --git a/src/bin/private_include/bin/mod.h b/src/bin/private_include/bin/mod.h
new file mode 100644
index 0000000..13ef55c
--- /dev/null
+++ b/src/bin/private_include/bin/mod.h
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_MOD_H
+#define BIN_MOD_H
+
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+#include <stddef.h>
+
+const struct bin_mod *bin_mod(const char *path);
+int bin_mod_lock(struct bin_mod *m);
+int bin_mod_unlock(struct bin_mod *m);
+int bin_mod_move(struct bin_mod *m, struct bin *from, struct bin *to);
+void bin_mod_free(struct bin_mod *m);
+int bin_mod_read(void *buf, size_t n, void *user);
+int bin_mod_eof(void *user);
+enum nw_state bin_mod_pc(long offset, struct nw_next *next, void *user);
+enum nw_state bin_mod_seek(long offset, void *user);
+enum nw_state bin_mod_tell(long *offset, void *user);
+
+extern const struct nw_mod_cfg bin_mod_cfg;
+
+#endif
diff --git a/src/bin/private_include/bin/proc.h b/src/bin/private_include/bin/proc.h
new file mode 100644
index 0000000..cf0c04e
--- /dev/null
+++ b/src/bin/private_include/bin/proc.h
@@ -0,0 +1,49 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_PROC_H
+#define BIN_PROC_H
+
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+#include <stddef.h>
+
+int bin_proc_init(struct bin_proc *p);
+int bin_proc_add(struct bin_proc *p);
+void bin_proc_free(struct bin_proc *p);
+int bin_proc_read(void *buf, size_t n, void *user);
+int bin_proc_eof(void *user);
+enum nw_state bin_proc_pc(long offset, struct nw_next *next, void *user);
+enum nw_state bin_proc_seek(long offset, void *user);
+enum nw_state bin_proc_tell(long *offset, void *user);
+int bin_proc_lock(struct bin_proc *p);
+int bin_proc_unlock(struct bin_proc *p);
+int bin_proc_move(struct bin_proc *p, struct bin *from, struct bin *to);
+int bin_proc_l_load(unsigned long pos, void *dst, size_t n, void *user);
+int bin_proc_l_store(unsigned long pos, const void *src, size_t n, void *user);
+int bin_proc_g_load(unsigned long pos, void *dst, size_t n, void *user);
+int bin_proc_g_store(unsigned long pos, const void *src, size_t n, void *user);
+int bin_proc_s_push(const void *src, size_t n, void *user);
+int bin_proc_s_pop(void *dst, size_t n, void *user);
+int bin_proc_s_read(size_t offset, void *dst, size_t n, void *user);
+int bin_proc_s_write(size_t offset, const void *dst, size_t n, void *user);
+size_t bin_proc_s_ptr(void *user);
+
+extern const struct nw_inst_cfg bin_proc_cfg;
+
+#endif
diff --git a/src/bin/private_include/bin/routines.h b/src/bin/private_include/bin/routines.h
new file mode 100644
index 0000000..c78ad18
--- /dev/null
+++ b/src/bin/private_include/bin/routines.h
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_ROUTINES_H
+#define BIN_ROUTINES_H
+
+#include <bin/types.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+pid_t bin_pid(void);
+int bin_start(struct bin_mod *m);
+int bin_stop(struct bin_proc *p);
+int bin_load(struct bin_mod *m);
+int bin_unload(struct bin_mod *m);
+
+#endif
diff --git a/src/bin/private_include/bin/types.h b/src/bin/private_include/bin/types.h
new file mode 100644
index 0000000..2a498ed
--- /dev/null
+++ b/src/bin/private_include/bin/types.h
@@ -0,0 +1,99 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_TYPES_H
+#define BIN_TYPES_H
+
+#include <bin/wasi.h>
+#include <caio.h>
+#include <fs/fs.h>
+#include <dynstr.h>
+#include <nanowasm/nw.h>
+#include <nanowasm/dbg.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+enum {BIN_IMPORTS = 9};
+
+struct bin_dbg
+{
+ char b;
+ bool running, step;
+ struct nw_dbg dbg;
+ struct dynstr dstr;
+ struct aio *aio;
+ struct fs_fd fd;
+ long *bkpt, offset;
+ size_t n_bkpt;
+};
+
+struct bin_stack
+{
+ struct page *page;
+ size_t sz, pi, n;
+};
+
+struct bin_global
+{
+ void *buf;
+ size_t sz;
+};
+
+struct bin_proc
+{
+ const struct bin_mod *mod;
+ struct nw_inst instance;
+ union nw_value args[7];
+ struct bin_dbg dbg;
+ struct caio *caio;
+ char *path, **argv;
+ size_t argc;
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+ char header[sizeof "asm"];
+ size_t i;
+ long retval;
+ struct bin_stack stack;
+ struct bin_global global;
+ void *import;
+ struct page *linear;
+ int *fds;
+ size_t n_fds;
+ struct bin_proc *prev, *next;
+};
+
+struct bin_mod
+{
+ char *path;
+ struct caio *caio;
+ struct nw_mod mod;
+ struct nw_mod_out mod_out;
+ struct nw_import_index import_indexes[BIN_IMPORTS];
+ struct bin_mod *prev, *next;
+};
+
+struct bin
+{
+ struct bin_mod *mod_head, *mod_tail;
+ struct bin_proc *proc_head, *proc_tail;
+};
+
+extern struct bin bin_active, bin_pending, bin_locked, bin_zombie;
+
+#endif
diff --git a/src/bin/private_include/bin/wasi.h b/src/bin/private_include/bin/wasi.h
new file mode 100644
index 0000000..c22c777
--- /dev/null
+++ b/src/bin/private_include/bin/wasi.h
@@ -0,0 +1,41 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_WASI_H
+#define BIN_WASI_H
+
+#include <nanowasm/nw.h>
+
+enum nw_state bin_wasi_proc_exit(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wasi_fd_prestat_get(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wasi_fd_prestat_dir_name(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wasi_path_create_directory(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wasi_fd_close(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wasi_fd_fdstat_get(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wasi_fd_seek(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wasi_fd_write(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+
+#endif
diff --git a/src/bin/private_include/bin/wasi/errno.h b/src/bin/private_include/bin/wasi/errno.h
new file mode 100644
index 0000000..442e877
--- /dev/null
+++ b/src/bin/private_include/bin/wasi/errno.h
@@ -0,0 +1,105 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef WASI_ERRNO_H
+#define WASI_ERRNO_H
+
+enum wasi_errno
+{
+ WASI_SUCCESS,
+ WASI_2BIG,
+ WASI_ACCES,
+ WASI_ADDRINUSE,
+ WASI_ADDRNOTAVAIL,
+ WASI_AFNOSUPPORT,
+ WASI_AGAIN,
+ WASI_ALREADY,
+ WASI_BADF,
+ WASI_BADMSG,
+ WASI_BUSY,
+ WASI_CANCELED,
+ WASI_CHILD,
+ WASI_CONNABORTED,
+ WASI_CONNREFUSED,
+ WASI_CONNRESET,
+ WASI_DEADLK,
+ WASI_DESTADDRREQ,
+ WASI_DOM,
+ WASI_DQUOT,
+ WASI_EXIST,
+ WASI_FAULT,
+ WASI_FBIG,
+ WASI_HOSTUNREACH,
+ WASI_IDRM,
+ WASI_ILSEQ,
+ WASI_INPROGRESS,
+ WASI_INTR,
+ WASI_INVAL,
+ WASI_IO,
+ WASI_ISCONN,
+ WASI_ISDIR,
+ WASI_LOOP,
+ WASI_MFILE,
+ WASI_MLINK,
+ WASI_MSGSIZE,
+ WASI_MULTIHOP,
+ WASI_NAMETOOLONG,
+ WASI_NETDOWN,
+ WASI_NETRESET,
+ WASI_NETUNREACH,
+ WASI_NFILE,
+ WASI_NOBUFS,
+ WASI_NODEV,
+ WASI_NOENT,
+ WASI_NOEXEC,
+ WASI_NOLCK,
+ WASI_NOLINK,
+ WASI_NOMEM,
+ WASI_NOMSG,
+ WASI_NOPROTOOPT,
+ WASI_NOSPC,
+ WASI_NOSYS,
+ WASI_NOTCONN,
+ WASI_NOTDIR,
+ WASI_NOTEMPTY,
+ WASI_NOTRECOVERABLE,
+ WASI_NOTSOCK,
+ WASI_NOTSUP,
+ WASI_NOTTY,
+ WASI_NXIO,
+ WASI_OVERFLOW,
+ WASI_OWNERDEAD,
+ WASI_PERM,
+ WASI_PIPE,
+ WASI_PROTO,
+ WASI_PROTONOSUPPORT,
+ WASI_PROTOTYPE,
+ WASI_RANGE,
+ WASI_ROFS,
+ WASI_SPIPE,
+ WASI_SRCH,
+ WASI_STALE,
+ WASI_TIMEDOUT,
+ WASI_TXTBSY,
+ WASI_XDEV,
+ WASI_NOTCAPABLE
+};
+
+int wasi_errno(int error, enum wasi_errno *out);
+
+#endif
diff --git a/src/bin/private_include/bin/wnix.h b/src/bin/private_include/bin/wnix.h
new file mode 100644
index 0000000..07e7131
--- /dev/null
+++ b/src/bin/private_include/bin/wnix.h
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_WNIX_H
+#define BIN_WNIX_H
+
+#include <nanowasm/nw.h>
+
+enum nw_state bin_wnix_exit(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_argc(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_arglen(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_argcopy(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_mkdir(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+enum nw_state bin_wnix_mount(const union nw_value *params,
+ union nw_value *ret, void *user, struct nw_next *next);
+
+#endif
diff --git a/src/bin/private_include/bin/wnix/routines.h b/src/bin/private_include/bin/wnix/routines.h
new file mode 100644
index 0000000..aa488fb
--- /dev/null
+++ b/src/bin/private_include/bin/wnix/routines.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef BIN_WNIX_ROUTINES_H
+#define BIN_WNIX_ROUTINES_H
+
+#include <bin.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+int bin_wnix_set_errno(struct bin_proc *p, int error, unsigned long addr,
+ struct nw_next *next);
+
+#endif
diff --git a/src/bin/src/CMakeLists.txt b/src/bin/src/CMakeLists.txt
new file mode 100644
index 0000000..0057f11
--- /dev/null
+++ b/src/bin/src/CMakeLists.txt
@@ -0,0 +1,30 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ exec.c
+ globals.c
+ load.c
+ loaded.c
+ pid.c
+ start.c
+ stop.c
+ update.c
+)
+
+add_subdirectory(wnix)
+add_subdirectory(mod)
+add_subdirectory(proc)
diff --git a/src/bin/src/exec.c b/src/bin/src/exec.c
new file mode 100644
index 0000000..83c0e5f
--- /dev/null
+++ b/src/bin/src/exec.c
@@ -0,0 +1,372 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/proc.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+#include <aio.h>
+#include <caio.h>
+#include <fs/fs.h>
+#include <loop.h>
+#include <kprintf.h>
+#include <dynstr.h>
+#include <nanowasm/nw.h>
+#include <nanowasm/dbg.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct exec
+{
+ struct bin_mod *m;
+ struct bin_proc *p;
+};
+
+static int announced(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct bin_dbg *const d = &p->dbg;
+ const struct nw_dbg_cfg cfg = {.inst = &p->instance};
+
+ dynstr_free(&d->dstr);
+
+ if (loop_rm_aio(d->aio))
+ goto failure;
+
+ aio_free(d->aio);
+
+ if (state)
+ kprintf("failed to announce process to debugger: %s\n", p->path);
+ else
+ nw_dbg_init(&d->dbg, &cfg);
+
+ return 0;
+
+failure:
+ bin_proc_free(p);
+ return -1;
+}
+
+static int announce(struct bin_proc *const p)
+{
+ struct aio *aio = NULL;
+ struct bin_dbg *const dbg = &p->dbg;
+ struct dynstr *const s = &dbg->dstr;
+ const struct aio_done d =
+ {
+ .f = announced,
+ .args = p
+ };
+
+ dynstr_init(s);
+
+ if (dynstr_append(s, ";hi:%s:%u\n", p->path, (unsigned)p->pid))
+ goto failure;
+
+ const struct fs_write w =
+ {
+ .buf = s->str,
+ .n = s->len + 1,
+ .fd = &dbg->fd
+ };
+
+ if (!(aio = aio_write(&w, &d)) || loop_add_aio(aio))
+ goto failure;
+
+ dbg->aio = aio;
+ return 0;
+
+failure:
+ aio_free(aio);
+ return -1;
+}
+
+static int mod_opened(const enum state state, void *const args)
+{
+ struct exec *const e = args;
+ struct bin_mod *const m = e->m;
+ struct bin_proc *const p = e->p;
+ struct nw_mod_cfg cfg = bin_mod_cfg;
+
+ cfg.io.user = m;
+ cfg.imp_indexes = m->import_indexes;
+ nw_init(&m->mod, &cfg);
+
+ if (state)
+ goto failure;
+ else if (bin_load(m)
+ || bin_proc_init(p)
+ || announce(p))
+ goto failure;
+
+ return 0;
+
+failure:
+ bin_mod_free(m);
+ return -1;
+}
+
+static int init_mod(struct bin_proc *const p)
+{
+ struct caio *caio = NULL;
+ char *const pathdup = strdup(p->path);
+ struct exec *const e = malloc(sizeof *e);
+ struct bin_mod *const m = malloc(sizeof *m);
+ const struct caio_open op =
+ {
+ .flags = O_RDONLY,
+ .path = p->path,
+ .gid = p->gid,
+ .uid = p->uid
+ };
+
+ const struct aio_done d =
+ {
+ .f = mod_opened,
+ .args = e,
+ };
+
+ if (!pathdup || !e || !m || !(caio = caio_open(&op, &d)))
+ goto failure;
+
+ *m = (const struct bin_mod)
+ {
+ .path = pathdup,
+ .caio = caio
+ };
+
+ *e = (const struct exec)
+ {
+ .m = m,
+ .p = p
+ };
+
+ p->mod = m;
+ return 0;
+
+failure:
+ caio_close(caio);
+ free(pathdup);
+ free(m);
+ free(e);
+ return -1;
+}
+
+static int header_read(struct bin_proc *const p)
+{
+ static const char shebang[] = "#! ", wasm[] = {'\0', 'a', 's', 'm'};
+ const char *const h = p->header;
+
+ if (!strncmp(h, shebang, strlen(shebang)))
+ {
+ /* TODO: interpret shebang */
+ }
+ else if (!memcmp(h, wasm, sizeof wasm))
+ {
+ if (init_mod(p))
+ goto failure;
+ }
+ else
+ {
+ kprintf("Invalid file signature: {%hhx, %hhx, %hhx, %hhx}\n",
+ h[0], h[1], h[2], h[3]);
+ goto failure;
+ }
+
+ if (caio_seek(p->caio, 0))
+ goto failure;
+
+ return 0;
+
+failure:
+ bin_proc_free(p);
+ return -1;
+}
+
+static int read_header(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+
+ if (state)
+ goto failure;
+
+ const size_t rem = sizeof p->header - p->i;
+ const struct aio_done d = {.f = read_header, .args = p};
+ const int n = caio_read(p->caio, p->header + p->i, rem, &d);
+
+ if (n < 0)
+ goto failure;
+ else if ((p->i += n) >= sizeof p->header)
+ return header_read(p);
+
+ return 0;
+
+failure:
+ bin_proc_free(p);
+ return -1;
+}
+
+static int opened(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+
+ if (state)
+ goto failure;
+ else if ((p->mod = bin_mod(p->path)))
+ return bin_proc_init(p);
+
+ p->i = 0;
+ return read_header(STATE_OK, p);
+
+failure:
+ bin_proc_free(p);
+ return -1;
+}
+
+static int serial_opened(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct bin_dbg *const dbg = &p->dbg;
+ struct caio *caio = NULL;
+ const struct aio_done d =
+ {
+ .f = opened,
+ .args = p
+ };
+
+ const struct caio_open op =
+ {
+ .flags = O_RDONLY,
+ .path = p->path,
+ .uid = p->uid,
+ .gid = p->gid
+ };
+
+ if (loop_rm_aio(dbg->aio))
+ goto failure;
+
+ aio_free(dbg->aio);
+ dbg->aio = NULL;
+
+ if (state
+ || !(caio = caio_open(&op, &d))
+ || caio_set_caches(caio, 3))
+ goto failure;
+
+ p->caio = caio;
+ return 0;
+
+failure:
+ caio_close(caio);
+ bin_proc_free(p);
+ return -1;
+}
+
+static int copy_args(struct bin_proc *const p, const char *const path,
+ const char *const *const argv)
+{
+ int nargs = 2;
+ const char *const *parg = argv;
+ char **args = NULL;
+
+ while (*parg++)
+ nargs++;
+
+ if (!(args = malloc(nargs * sizeof *args)))
+ goto failure;
+
+ for (int i = 0; i < nargs; i++)
+ args[i] = NULL;
+
+ if (!(*args = strdup(path)))
+ goto failure;
+
+ for (int i = 1; i < nargs - 1; i++)
+ if (!(args[i] = strdup(*(argv - 1))))
+ goto failure;
+
+ p->argc = nargs - 1;
+ p->argv = args;
+ return 0;
+
+failure:
+
+ if (args)
+ for (int i = 0; i < nargs; i++)
+ free(args[i]);
+
+ free(args);
+ return -1;
+}
+
+int bin_exec(const char *const path, const char *const *const argv,
+ const uid_t uid, const gid_t gid)
+{
+ const pid_t pid = bin_pid();
+ char *pathdup = NULL;
+ struct aio *serial = NULL;
+ struct bin_proc *const p = malloc(sizeof *p);
+
+ if (!p)
+ goto failure;
+
+ struct bin_dbg *const dbg = &p->dbg;
+
+ const struct aio_done d =
+ {
+ .f = serial_opened,
+ .args = p
+ };
+
+ const struct fs_open op =
+ {
+ .path = "/dev/ttyS0",
+ .flags = O_RDWR,
+ .fd = &dbg->fd,
+ .uid = uid,
+ .gid = gid
+ };
+
+ if (!(pathdup = strdup(path))
+ || !(serial = aio_open(&op, &d)))
+ goto failure;
+
+ *p = (const struct bin_proc)
+ {
+ .path = pathdup,
+ .dbg.aio = serial,
+ .pid = pid,
+ .uid = uid,
+ .gid = gid
+ };
+
+ if (copy_args(p, path, argv)
+ || loop_add_aio(serial))
+ goto failure;
+
+ return 0;
+
+failure:
+ aio_free(serial);
+ free(pathdup);
+ free(p);
+ return -1;
+}
diff --git a/src/bin/src/globals.c b/src/bin/src/globals.c
new file mode 100644
index 0000000..ffab850
--- /dev/null
+++ b/src/bin/src/globals.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/types.h>
+
+struct bin bin_active, bin_pending, bin_locked, bin_zombie;
diff --git a/src/bin/src/load.c b/src/bin/src/load.c
new file mode 100644
index 0000000..4a2ab95
--- /dev/null
+++ b/src/bin/src/load.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+int bin_load(struct bin_mod *const m)
+{
+ return bin_mod_move(m, NULL, &bin_pending);
+}
diff --git a/src/bin/src/loaded.c b/src/bin/src/loaded.c
new file mode 100644
index 0000000..931807b
--- /dev/null
+++ b/src/bin/src/loaded.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <stddef.h>
+#include <string.h>
+
+const struct bin_mod *bin_mod(const char *const path)
+{
+ for (const struct bin_mod *m = bin_active.mod_head; m; m = m->next)
+ if (!strcmp(m->path, path))
+ return m;
+
+ return NULL;
+}
diff --git a/src/bin/src/mod/CMakeLists.txt b/src/bin/src/mod/CMakeLists.txt
new file mode 100644
index 0000000..0976111
--- /dev/null
+++ b/src/bin/src/mod/CMakeLists.txt
@@ -0,0 +1,29 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ cfg.c
+ eof.c
+ free.c
+ lock.c
+ move.c
+ pc.c
+ read.c
+ seek.c
+ tell.c
+ unload.c
+ unlock.c
+)
diff --git a/src/bin/src/mod/cfg.c b/src/bin/src/mod/cfg.c
new file mode 100644
index 0000000..8c78a32
--- /dev/null
+++ b/src/bin/src/mod/cfg.c
@@ -0,0 +1,106 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+static const struct nw_import imports[BIN_IMPORTS] =
+{
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "exit",
+ .u.function =
+ {
+ .fn = bin_wnix_exit,
+ .signature = "(i)"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "argc",
+ .u.function =
+ {
+ .fn = bin_wnix_argc,
+ .signature = "i()"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "arglen",
+ .u.function =
+ {
+ .fn = bin_wnix_arglen,
+ .signature = "i(i)"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "argcopy",
+ .u.function =
+ {
+ .fn = bin_wnix_argcopy,
+ .signature = "i(iii)"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "mkdir",
+ .u.function =
+ {
+ .fn = bin_wnix_mkdir,
+ .signature = "i(iii)"
+ }
+ },
+
+ {
+ .kind = NW_KIND_FUNCTION,
+ .module = "wnix",
+ .field = "mount",
+ .u.function =
+ {
+ .fn = bin_wnix_mount,
+ .signature = "i(iiiiii)"
+ }
+ }
+};
+
+const struct nw_mod_cfg bin_mod_cfg =
+{
+ .imports = imports,
+ .n_imports = sizeof imports / sizeof *imports,
+ .io =
+ {
+ .read = bin_mod_read,
+ .eof = bin_mod_eof,
+ .pc = bin_mod_pc,
+ .seek = bin_mod_seek,
+ .tell = bin_mod_tell,
+ }
+};
diff --git a/src/bin/src/mod/eof.c b/src/bin/src/mod/eof.c
new file mode 100644
index 0000000..291d400
--- /dev/null
+++ b/src/bin/src/mod/eof.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+
+int bin_mod_eof(void *const user)
+{
+ const struct bin_mod *const m = user;
+
+ return caio_eof(m->caio);
+}
diff --git a/src/bin/src/mod/free.c b/src/bin/src/mod/free.c
new file mode 100644
index 0000000..8b790bb
--- /dev/null
+++ b/src/bin/src/mod/free.c
@@ -0,0 +1,33 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <caio.h>
+#include <stdlib.h>
+
+void bin_mod_free(struct bin_mod *const p)
+{
+ if (!p)
+ return;
+
+ caio_close(p->caio);
+ free(p->path);
+ free(p);
+}
diff --git a/src/bin/src/mod/lock.c b/src/bin/src/mod/lock.c
new file mode 100644
index 0000000..89ab732
--- /dev/null
+++ b/src/bin/src/mod/lock.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+
+int bin_mod_lock(struct bin_mod *const m)
+{
+ return bin_mod_move(m, &bin_pending, &bin_locked);
+}
diff --git a/src/bin/src/mod/move.c b/src/bin/src/mod/move.c
new file mode 100644
index 0000000..84c6cb4
--- /dev/null
+++ b/src/bin/src/mod/move.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+int bin_mod_move(struct bin_mod *const m, struct bin *const from,
+ struct bin *const to)
+{
+ if (from)
+ {
+ if (from->mod_head == m)
+ from->mod_head = m->next;
+
+ if (from->mod_tail == m)
+ from->mod_tail = m->prev;
+ }
+
+ if (m->next)
+ m->next->prev = m->prev;
+
+ if (m->prev)
+ m->prev->next = m->next;
+
+ if (to)
+ {
+ if (!to->mod_head)
+ {
+ to->mod_head = m;
+ m->prev = m->next = NULL;
+ }
+ else
+ {
+ struct bin_mod *const t = to->mod_tail;
+
+ t->next = m;
+ m->prev = t;
+ m->next = NULL;
+ }
+
+ to->mod_tail = m;
+ }
+
+ return 0;
+}
diff --git a/src/bin/src/mod/pc.c b/src/bin/src/mod/pc.c
new file mode 100644
index 0000000..bb9f84e
--- /dev/null
+++ b/src/bin/src/mod/pc.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_mod_pc(const long offset, struct nw_next *const next,
+ void *const user)
+{
+ /* TODO: will this be ever used? */
+ return NW_OK;
+}
diff --git a/src/bin/src/mod/read.c b/src/bin/src/mod/read.c
new file mode 100644
index 0000000..7e0919f
--- /dev/null
+++ b/src/bin/src/mod/read.c
@@ -0,0 +1,53 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <caio.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+static int done(const enum state state, void *const args)
+{
+ struct bin_mod *const m = args;
+
+ if (state)
+ return -1;
+
+ return bin_mod_unlock(m);
+}
+
+int bin_mod_read(void *const buf, const size_t n, void *const user)
+{
+ struct bin_mod *const m = user;
+ const struct aio_done d =
+ {
+ .f = done,
+ .args = m
+ };
+
+ const int r = caio_read(m->caio, buf, n, &d);
+
+ if (r < 0)
+ return -1;
+ else if (!r && !caio_eof(m->caio))
+ return bin_mod_lock(m);
+
+ return r;
+}
diff --git a/src/bin/src/mod/seek.c b/src/bin/src/mod/seek.c
new file mode 100644
index 0000000..6d51049
--- /dev/null
+++ b/src/bin/src/mod/seek.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_mod_seek(const long offset, void *const user)
+{
+ struct bin_mod *const m = user;
+
+ return caio_seek(m->caio, offset) ? NW_FATAL : NW_OK;
+}
diff --git a/src/bin/src/mod/tell.c b/src/bin/src/mod/tell.c
new file mode 100644
index 0000000..c027c8c
--- /dev/null
+++ b/src/bin/src/mod/tell.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_mod_tell(long *const offset, void *const user)
+{
+ const struct bin_mod *const m = user;
+ off_t off;
+
+ if (caio_tell(m->caio, &off))
+ return NW_FATAL;
+
+ *offset = off;
+ return NW_OK;
+}
diff --git a/src/bin/src/mod/unload.c b/src/bin/src/mod/unload.c
new file mode 100644
index 0000000..3f0b80b
--- /dev/null
+++ b/src/bin/src/mod/unload.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+
+int bin_unload(struct bin_mod *const m)
+{
+ struct bin *const b = &bin_pending;
+
+ if (b->mod_head == m)
+ b->mod_head = m->next;
+
+ if (b->mod_tail == m)
+ b->mod_tail = m->prev;
+
+ if (m->next)
+ m->next->prev = m->prev;
+
+ if (m->prev)
+ m->prev->next = m->next;
+
+ return 0;
+}
diff --git a/src/bin/src/mod/unlock.c b/src/bin/src/mod/unlock.c
new file mode 100644
index 0000000..61a3002
--- /dev/null
+++ b/src/bin/src/mod/unlock.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+int bin_mod_unlock(struct bin_mod *const m)
+{
+ return bin_mod_move(m, &bin_locked, &bin_pending);
+}
diff --git a/src/bin/src/pid.c b/src/bin/src/pid.c
new file mode 100644
index 0000000..bbbca78
--- /dev/null
+++ b/src/bin/src/pid.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/types.h>
+#include <bin/routines.h>
+#include <sys/types.h>
+
+pid_t bin_pid(void)
+{
+ static pid_t pid;
+
+ return ++pid;
+}
diff --git a/src/bin/src/proc/CMakeLists.txt b/src/bin/src/proc/CMakeLists.txt
new file mode 100644
index 0000000..47df502
--- /dev/null
+++ b/src/bin/src/proc/CMakeLists.txt
@@ -0,0 +1,33 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ cfg.c
+ eof.c
+ free.c
+ init.c
+ lock.c
+ move.c
+ pc.c
+ read.c
+ seek.c
+ tell.c
+ unlock.c
+)
+
+add_subdirectory(global)
+add_subdirectory(linear)
+add_subdirectory(stack)
diff --git a/src/bin/src/proc/cfg.c b/src/bin/src/proc/cfg.c
new file mode 100644
index 0000000..efe6333
--- /dev/null
+++ b/src/bin/src/proc/cfg.c
@@ -0,0 +1,59 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+const struct nw_inst_cfg bin_proc_cfg =
+{
+ .entry = "_start",
+ .interp_cfg =
+ {
+ .io =
+ {
+ .read = bin_proc_read,
+ .eof = bin_proc_eof,
+ .seek = bin_proc_seek,
+ .tell = bin_proc_tell,
+ .pc = bin_proc_pc
+ },
+
+ .global =
+ {
+ .load = bin_proc_g_load,
+ .store = bin_proc_g_store
+ },
+
+ .linear =
+ {
+ .load = bin_proc_l_load,
+ .store = bin_proc_l_store
+ },
+
+ .stack =
+ {
+ .push = bin_proc_s_push,
+ .pop = bin_proc_s_pop,
+ .read = bin_proc_s_read,
+ .write = bin_proc_s_write,
+ .ptr = bin_proc_s_ptr
+ }
+ }
+};
diff --git a/src/bin/src/proc/eof.c b/src/bin/src/proc/eof.c
new file mode 100644
index 0000000..c1d75e5
--- /dev/null
+++ b/src/bin/src/proc/eof.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+
+int bin_proc_eof(void *const user)
+{
+ const struct bin_proc *const p = user;
+
+ return caio_eof(p->caio);
+}
diff --git a/src/bin/src/proc/free.c b/src/bin/src/proc/free.c
new file mode 100644
index 0000000..a5bdea1
--- /dev/null
+++ b/src/bin/src/proc/free.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <aio.h>
+#include <caio.h>
+#include <stdlib.h>
+
+void bin_proc_free(struct bin_proc *const p)
+{
+ if (!p)
+ return;
+
+ struct bin_dbg *const d = &p->dbg;
+
+ dynstr_free(&d->dstr);
+ free(d->bkpt);
+ aio_free(d->aio);
+ caio_close(p->caio);
+ free(p->global.buf);
+ free(p->path);
+ free(p);
+}
diff --git a/src/bin/src/proc/global/CMakeLists.txt b/src/bin/src/proc/global/CMakeLists.txt
new file mode 100644
index 0000000..bd445a4
--- /dev/null
+++ b/src/bin/src/proc/global/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ load.c
+ store.c
+)
diff --git a/src/bin/src/proc/global/load.c b/src/bin/src/proc/global/load.c
new file mode 100644
index 0000000..172ab14
--- /dev/null
+++ b/src/bin/src/proc/global/load.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <kprintf.h>
+#include <stddef.h>
+#include <string.h>
+
+int bin_proc_g_load(const unsigned long pos, void *const dst, const size_t n,
+ void *const user)
+{
+ struct bin_proc *const p = user;
+ struct bin_global *const g = &p->global;
+
+ if (n > g->sz || pos > g->sz - n)
+ {
+ kprintf("%s: out-of-bounds access to global memory\n", p->path);
+ return -1;
+ }
+
+ memcpy(dst, (const char *)g->buf + pos, n);
+ return n;
+}
diff --git a/src/bin/src/proc/global/store.c b/src/bin/src/proc/global/store.c
new file mode 100644
index 0000000..da7657e
--- /dev/null
+++ b/src/bin/src/proc/global/store.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <kprintf.h>
+#include <stddef.h>
+#include <string.h>
+
+int bin_proc_g_store(const unsigned long pos, const void *const src,
+ const size_t n, void *const user)
+{
+ struct bin_proc *const p = user;
+ struct bin_global *const g = &p->global;
+
+ if (n > g->sz || pos > g->sz - n)
+ {
+ kprintf("%s: out-of-bounds access to global memory\n", p->path);
+ return -1;
+ }
+
+ memcpy((char *)g->buf + pos, src, n);
+ return n;
+}
diff --git a/src/bin/src/proc/init.c b/src/bin/src/proc/init.c
new file mode 100644
index 0000000..9a39c73
--- /dev/null
+++ b/src/bin/src/proc/init.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+int bin_proc_init(struct bin_proc *const p)
+{
+ struct nw_inst_cfg icfg = bin_proc_cfg;
+ struct nw_interp_cfg *const i = &icfg.interp_cfg;
+
+ i->user = i->io.user = p;
+ i->m = &p->mod->mod;
+ i->args = p->args;
+ i->n_args = sizeof p->args / sizeof *p->args;
+
+ if (nw_start(&p->instance, &icfg))
+ return -1;
+
+ return bin_proc_move(p, NULL, &bin_pending);
+}
diff --git a/src/bin/src/proc/linear/CMakeLists.txt b/src/bin/src/proc/linear/CMakeLists.txt
new file mode 100644
index 0000000..bd445a4
--- /dev/null
+++ b/src/bin/src/proc/linear/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ load.c
+ store.c
+)
diff --git a/src/bin/src/proc/linear/load.c b/src/bin/src/proc/linear/load.c
new file mode 100644
index 0000000..5881c69
--- /dev/null
+++ b/src/bin/src/proc/linear/load.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <page.h>
+#include <stddef.h>
+
+int bin_proc_l_load(const unsigned long pos, void *const dst, const size_t n,
+ void *const user)
+{
+ /* TODO: make nanowasm check linear memory accesses. */
+ struct bin_proc *const p = user;
+ const int w = page_read(&p->linear, pos, dst, n);
+
+ if (w < 0)
+ return -1;
+#if 0
+ else if (!w)
+ /* TODO: how to unlock? */
+ return bin_proc_lock(p);
+#endif
+
+ return w;
+}
diff --git a/src/bin/src/proc/linear/store.c b/src/bin/src/proc/linear/store.c
new file mode 100644
index 0000000..22f9891
--- /dev/null
+++ b/src/bin/src/proc/linear/store.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <page.h>
+#include <stddef.h>
+
+int bin_proc_l_store(const unsigned long pos, const void *const src,
+ const size_t n, void *const user)
+{
+ /* TODO: make nanowasm check linear memory accesses. */
+ struct bin_proc *const p = user;
+ const int w = page_write(&p->linear, pos, src, n);
+
+ if (w < 0)
+ return -1;
+#if 0
+ else if (!w)
+ /* TODO: how to unlock? */
+ return bin_proc_lock(p);
+#endif
+
+ return w;
+}
diff --git a/src/bin/src/proc/lock.c b/src/bin/src/proc/lock.c
new file mode 100644
index 0000000..479e902
--- /dev/null
+++ b/src/bin/src/proc/lock.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+int bin_proc_lock(struct bin_proc *const p)
+{
+ return bin_proc_move(p, &bin_active, &bin_locked);
+}
diff --git a/src/bin/src/proc/move.c b/src/bin/src/proc/move.c
new file mode 100644
index 0000000..7192457
--- /dev/null
+++ b/src/bin/src/proc/move.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+int bin_proc_move(struct bin_proc *const p, struct bin *const from,
+ struct bin *const to)
+{
+ if (from)
+ {
+ if (from->proc_head == p)
+ from->proc_head = p->next;
+
+ if (from->proc_tail == p)
+ from->proc_tail = p->prev;
+ }
+
+ if (p->next)
+ p->next->prev = p->prev;
+
+ if (p->prev)
+ p->prev->next = p->next;
+
+ if (to)
+ {
+ if (!to->proc_head)
+ {
+ to->proc_head = p;
+ p->prev = p->next = NULL;
+ }
+ else
+ {
+ struct bin_proc *const t = to->proc_tail;
+
+ t->next = p;
+ p->prev = t;
+ p->next = NULL;
+ }
+
+ to->proc_tail = p;
+ }
+
+ return 0;
+}
diff --git a/src/bin/src/proc/pc.c b/src/bin/src/proc/pc.c
new file mode 100644
index 0000000..746e418
--- /dev/null
+++ b/src/bin/src/proc/pc.c
@@ -0,0 +1,666 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <aio.h>
+#include <kprintf.h>
+#include <loop.h>
+#include <state.h>
+#include <dynstr.h>
+#include <nanowasm/nw.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+static enum nw_state check_start(void *, struct nw_next *);
+static int read_string(struct bin_proc *, struct nw_next *);
+
+static int read_done(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct bin_dbg *const d = &p->dbg;
+
+ if (loop_rm_aio(d->aio) || bin_proc_unlock(p))
+ return -1;
+
+ aio_free(d->aio);
+ d->aio = NULL;
+ return 0;
+}
+
+static int read_byte(struct bin_proc *const p)
+{
+ struct bin_dbg *const d = &p->dbg;
+
+ const struct fs_read r =
+ {
+ .fd = &d->fd,
+ .buf = &d->b,
+ .n = sizeof d->b
+ };
+
+ const struct aio_done done =
+ {
+ .f = read_done,
+ .args = p
+ };
+
+ struct aio *const aio = aio_read(&r, &done);
+
+ if (!aio
+ || loop_add_aio(aio)
+ || bin_proc_lock(p))
+ goto failure;
+
+ d->aio = aio;
+ return 0;
+
+failure:
+ aio_free(aio);
+ return -1;
+}
+
+static const char *token(const char *s, size_t *const n,
+ const char **const next)
+{
+ const char *const sep = strchr(s, ':');
+
+ if (sep)
+ {
+ *n = sep - s;
+ *next = sep + 1;
+ }
+ else
+ {
+ *n = sep ? sep - s : strlen(s);
+ *next = NULL;
+ }
+
+ return s;
+}
+
+static int parse_num(const char *const s, unsigned long *const out)
+{
+ char *end;
+ unsigned long v;
+
+ errno = 0;
+ v = strtoul(s, &end, 0);
+
+ if (errno || *end)
+ return -1;
+
+ *out = v;
+ return 0;
+}
+
+static int replied(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct bin_dbg *const d = &p->dbg;
+
+ if (loop_rm_aio(d->aio) || bin_proc_unlock(p))
+ return -1;
+
+ aio_free(d->aio);
+ d->aio = NULL;
+ return 0;
+}
+
+static enum nw_state finished(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct bin_dbg *const d = &p->dbg;
+
+ dynstr_free(&d->dstr);
+
+ if (d->running)
+ return NW_OK;
+
+ *next = (const struct nw_next){.fn = check_start, .user = p};
+ return NW_AGAIN;
+}
+
+static enum nw_state reply(struct bin_proc *const p, struct nw_next *const next,
+ const char *const s)
+{
+ struct aio *aio = NULL;
+ struct bin_dbg *const d = &p->dbg;
+ const struct fs_write w =
+ {
+ .fd = &d->fd,
+ .buf = s,
+ .n = strlen(s)
+ };
+
+ const struct aio_done done =
+ {
+ .f = replied,
+ .args = p
+ };
+
+ if (!(aio = aio_write(&w, &done))
+ || loop_add_aio(aio)
+ || bin_proc_lock(p))
+ goto failure;
+
+ d->aio = aio;
+ *next = (const struct nw_next){.fn = finished, .user = p};
+ return NW_AGAIN;
+
+failure:
+ aio_free(aio);
+ return NW_FATAL;
+}
+
+static int append_value(struct dynstr *const d,
+ const struct nw_dbg_value *const v)
+{
+ /* TODO: is %f valid for both float and double? */
+ static const char *const fmt[] =
+ {
+ [NW_TYPE_I32] = "%lu",
+ [NW_TYPE_I64] = "%llu",
+ [NW_TYPE_F32] = "%f",
+ [NW_TYPE_F64] = "%f"
+ };
+
+ return dynstr_append(d, fmt[v->type], v->value);
+}
+
+#include <drv/ps1/bios.h>
+static enum nw_state write_value(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct bin_dbg *const db = &p->dbg;
+ struct dynstr *const d = &db->dstr;
+ struct nw_dbg_value v;
+
+ dynstr_init(d);
+
+ if (nw_dbg_value(&db->dbg, &v)
+ || dynstr_append(d, ";ok:")
+ || append_value(d, &v)
+ || dynstr_append(d, "\n"))
+ return NW_FATAL;
+
+ Printf(">> %s", d->str);
+ return reply(user, next, d->str);
+}
+
+static enum nw_state trap(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct bin_dbg *const db = &p->dbg;
+ struct dynstr *const d = &db->dstr;
+
+ dynstr_init(d);
+
+ if (dynstr_append(d, ";trap:%#lx\n", db->offset))
+ return NW_FATAL;
+
+ return reply(user, next, d->str);
+}
+
+static enum nw_state ok(void *const user, struct nw_next *const next)
+{
+ return reply(user, next, ";ok\n");
+}
+
+static enum nw_state nok(void *const user, struct nw_next *const next)
+{
+ return reply(user, next, ";nok\n");
+}
+
+static int add_bkpt(struct bin_dbg *const d, const long addr)
+{
+ const size_t n = d->n_bkpt + 1;
+ long *const b = realloc(d->bkpt, n * sizeof *d->bkpt);
+
+ if (!b)
+ return -1;
+
+ b[d->n_bkpt] = addr;
+ d->bkpt = b;
+ d->n_bkpt = n;
+ return 0;
+}
+
+static int cmd_b(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ size_t tklen;
+ unsigned long addr;
+ struct bin_dbg *const d = &p->dbg;
+ const size_t n = d->n_bkpt;
+ const char *ntok, *const tk = token(s, &tklen, &ntok);
+
+ if (!tk || ntok)
+ {
+ kprintf("Syntax: b:<pc>\n");
+ return 1;
+ }
+ else if (parse_num(tk, &addr) || addr > LONG_MAX)
+ {
+ kprintf("Invalid value: %s\n", tk);
+ return 1;
+ }
+ else if (add_bkpt(d, addr))
+ return -1;
+ else
+ kprintf("Set breakpoint %zu at address %#lx\n", n, addr);
+
+ *next = (const struct nw_next){.fn = ok, .user = p};
+ return 0;
+}
+
+static int cmd_bt(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ /* TODO */
+ kprintf("%s: TODO\n", __func__);
+ return 1;
+}
+
+static int cmd_c(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ struct bin_dbg *const d = &p->dbg;
+
+ if (s)
+ {
+ kprintf("Syntax: c\n");
+ return 1;
+ }
+
+ d->running = true;
+ *next = (const struct nw_next){.fn = ok, .user = p};
+ return 0;
+}
+
+static int resize_bkpt(struct bin_dbg *const d, const unsigned long index)
+{
+ const size_t n = d->n_bkpt - 1;
+ long *const dst = &d->bkpt[index];
+
+ if (index < n)
+ memcpy(dst, dst + 1, (d->n_bkpt - index) * sizeof *dst);
+
+ if (n)
+ {
+ long *const b = realloc(d->bkpt, n * sizeof *d->bkpt);
+
+ if (!b)
+ return -1;
+
+ d->bkpt = b;
+ }
+ else
+ {
+ free(d->bkpt);
+ d->bkpt = NULL;
+ }
+
+ d->n_bkpt = n;
+ return 0;
+}
+
+static void delete_bkpt(struct bin_dbg *const d)
+{
+ free(d->bkpt);
+ d->bkpt = NULL;
+ d->n_bkpt = 0;
+}
+
+static int cmd_d(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ size_t tklen;
+ unsigned long index;
+ struct bin_dbg *const d = &p->dbg;
+ const char *ntok, *const tk = token(s, &tklen, &ntok);
+
+ if (!tk)
+ {
+ if (d->n_bkpt)
+ {
+ delete_bkpt(d);
+ kprintf("Deleted all breakpoints\n");
+ }
+ else
+ kprintf("No breakpoints to delete\n");
+ }
+ else if (ntok)
+ {
+ kprintf("Syntax: d[:<b-index>]\n");
+ return 1;
+ }
+ else if (parse_num(tk, &index) || index >= d->n_bkpt)
+ {
+ kprintf("Invalid breakpoint index: %s\n", tk);
+ return 1;
+ }
+ else if (resize_bkpt(d, index))
+ return -1;
+ else
+ kprintf("Deleted breakpoint index %lu\n", index);
+
+ *next = (const struct nw_next){.fn = ok, .user = p};
+ return 0;
+}
+
+static int cmd_g(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ size_t tklen;
+ unsigned long index;
+ struct bin_dbg *const d = &p->dbg;
+ const char *ntok, *const tk = token(s, &tklen, &ntok);
+
+ if (!tk || ntok)
+ {
+ kprintf("Syntax: g:<index>\n");
+ return 1;
+ }
+ else if (parse_num(tk, &index))
+ {
+ kprintf("Invalid value: %s\n", tk);
+ return 1;
+ }
+
+ nw_dbg_global(&d->dbg, index);
+ *next = (const struct nw_next){.fn = write_value, .user = p};
+ return 0;
+ return 1;
+}
+
+static int cmd_l(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ size_t tklen;
+ unsigned long index;
+ struct bin_dbg *const d = &p->dbg;
+ const char *ntok, *const tk = token(s, &tklen, &ntok);
+
+ if (!tk || ntok)
+ {
+ kprintf("Syntax: l:<index>\n");
+ return 1;
+ }
+ else if (parse_num(tk, &index))
+ {
+ kprintf("Invalid value: %s\n", tk);
+ return 1;
+ }
+
+ nw_dbg_local(&d->dbg, index);
+ *next = (const struct nw_next){.fn = write_value, .user = p};
+ return 0;
+}
+
+static int cmd_p(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ size_t tklen;
+ unsigned long index;
+ struct bin_dbg *const d = &p->dbg;
+ const char *ntok, *const tk = token(s, &tklen, &ntok);
+
+ if (!tk || ntok)
+ {
+ kprintf("Syntax: p:<index>\n");
+ return 1;
+ }
+ else if (parse_num(tk, &index))
+ {
+ kprintf("Invalid value: %s\n", tk);
+ return 1;
+ }
+
+ nw_dbg_param(&d->dbg, index);
+ *next = (const struct nw_next){.fn = write_value, .user = p};
+ return 0;
+}
+
+static int parse_type(const char *const s, enum nw_type *const out)
+{
+ switch (*s)
+ {
+ case 'i':
+ *out = NW_TYPE_I32;
+ break;
+
+ case 'I':
+ *out = NW_TYPE_I64;
+ break;
+
+ case 'f':
+ *out = NW_TYPE_F32;
+ break;
+
+ case 'F':
+ *out = NW_TYPE_F64;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int cmd_m(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ size_t tklen;
+ struct bin_dbg *const d = &p->dbg;
+ static const char exc[] = "Syntax: m:<i|I|f|F>:<addr>\n";
+ const char *ntok, *tk = token(s, &tklen, &ntok);
+ enum nw_type type;
+ unsigned long addr;
+
+ if (!tk || tklen != 1 || !ntok)
+ {
+ kprintf(exc);
+ return 1;
+ }
+ else if (parse_type(tk, &type))
+ {
+ kprintf("Invalid type specifier: %.*s\n", (int)tklen, tk);
+ return 1;
+ }
+ else if (!token(tk = ntok, &tklen, &ntok) || ntok)
+ {
+ kprintf(exc);
+ return 1;
+ }
+ else if (parse_num(tk, &addr))
+ {
+ kprintf("Invalid address: %s\n", tk);
+ return 1;
+ }
+
+ *next = (const struct nw_next){.fn = write_value, .user = p};
+ nw_dbg_mem_load(&d->dbg, type, addr);
+ return 0;
+}
+
+static int cmd_s(struct bin_proc *const p, const char *const s,
+ struct nw_next *const next)
+{
+ struct bin_dbg *const d = &p->dbg;
+
+ if (s)
+ {
+ kprintf("Syntax: s\n");
+ return 1;
+ }
+
+ d->running = d->step = true;
+ *next = (const struct nw_next){.fn = ok, .user = p};
+ return 0;
+}
+
+static int parse_cmd(struct bin_proc *const p, const char *const tk,
+ const size_t tklen, const char *const ntk, struct nw_next *const next)
+{
+ static const struct cmd
+ {
+ const char *cmd;
+ int (*f)(struct bin_proc *, const char *, struct nw_next *);
+ } cmds[] =
+ {
+ {.cmd = "b", .f = cmd_b},
+ {.cmd = "bt", .f = cmd_bt},
+ {.cmd = "c", .f = cmd_c},
+ {.cmd = "d", .f = cmd_d},
+ {.cmd = "g", .f = cmd_g},
+ {.cmd = "l", .f = cmd_l},
+ {.cmd = "m", .f = cmd_m},
+ {.cmd = "p", .f = cmd_p},
+ {.cmd = "s", .f = cmd_s}
+ };
+
+ for (size_t i = 0; i < sizeof cmds / sizeof *cmds; i++)
+ {
+ const struct cmd *const c = &cmds[i];
+
+ if (!strncmp(c->cmd, tk, tklen))
+ return c->f(p, ntk, next);
+ }
+
+ kprintf("Unknown command %.*s\n", (int)tklen, tk);
+ return 1;
+}
+
+static int parse(struct bin_proc *const p, struct nw_next *const next)
+{
+ struct bin_dbg *const dbg = &p->dbg;
+ struct dynstr *const d = &dbg->dstr;
+ const char *const s = d->str, *tk, *ntk;
+ size_t tklen;
+
+ if (!s || !(tk = token(s, &tklen, &ntk)) || !tklen)
+ return 1;
+
+ return parse_cmd(p, tk, tklen, ntk, next);
+}
+
+static enum nw_state check_lf(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct bin_dbg *const dbg = &p->dbg;
+ struct dynstr *const d = &dbg->dstr;
+ const char b = dbg->b;
+ const size_t max = 128;
+
+ Printf("%c", b);
+
+ if (b == ';')
+ {
+ dynstr_free(d);
+
+ if (read_string(p, next))
+ return NW_FATAL;
+ }
+ else if (b == '\n')
+ {
+ const int n = parse(p, next);
+
+ if (n < 0)
+ goto failure;
+ else if (n)
+ {
+ dynstr_free(d);
+ *next = (const struct nw_next){.fn = nok, .user = p};
+ }
+ }
+ else if (d->len < max)
+ if (dynstr_append(d, "%c", b) || read_byte(p))
+ goto failure;
+
+ return NW_AGAIN;
+
+failure:
+ dynstr_free(d);
+ return NW_FATAL;
+}
+
+static int read_string(struct bin_proc *const p, struct nw_next *const next)
+{
+ struct bin_dbg *const d = &p->dbg;
+
+ dynstr_init(&d->dstr);
+
+ if (read_byte(p))
+ return -1;
+
+ *next = (const struct nw_next){.fn = check_lf, .user = p};
+ return 0;
+}
+
+static enum nw_state check_start(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct bin_dbg *const d = &p->dbg;
+
+ Printf("<< %c", d->b);
+
+ if (d->b == ';')
+ {
+ if (read_string(p, next))
+ return NW_FATAL;
+ }
+ else if (read_byte(p))
+ return NW_FATAL;
+ else
+ Printf("(%#hhx)\n", d->b);
+
+ return NW_AGAIN;
+}
+
+enum nw_state bin_proc_pc(const long offset, struct nw_next *const next,
+ void *const user)
+{
+ struct bin_proc *const p = user;
+ struct bin_dbg *const d = &p->dbg;
+
+ if (!d->running || d->step)
+ {
+ d->step = d->running = false;
+ d->offset = offset;
+ *next = (const struct nw_next){.fn = trap, .user = p};
+ return NW_AGAIN;
+ }
+ else
+ for (size_t i = 0; i < d->n_bkpt; i++)
+ if (offset == d->bkpt[i])
+ {
+ kprintf("Reached breakpoint %zu at offset %#lx\n", i, offset);
+ d->running = d->step = false;
+ d->offset = offset;
+ *next = (const struct nw_next){.fn = trap, .user = p};
+ return NW_AGAIN;
+ }
+
+ return NW_OK;
+}
diff --git a/src/bin/src/proc/read.c b/src/bin/src/proc/read.c
new file mode 100644
index 0000000..f24a6ca
--- /dev/null
+++ b/src/bin/src/proc/read.c
@@ -0,0 +1,51 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+static int done(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+
+ if (state)
+ return -1;
+
+ return bin_proc_unlock(p);
+}
+
+int bin_proc_read(void *const buf, const size_t n, void *const user)
+{
+ struct bin_proc *const p = user;
+ const struct aio_done d =
+ {
+ .f = done,
+ .args = p
+ };
+
+ const int r = caio_read(p->caio, buf, n, &d);
+
+ if (r < 0)
+ return -1;
+ else if (!r && !caio_eof(p->caio))
+ return bin_proc_lock(p);
+
+ return r;
+}
diff --git a/src/bin/src/proc/seek.c b/src/bin/src/proc/seek.c
new file mode 100644
index 0000000..24b1a2f
--- /dev/null
+++ b/src/bin/src/proc/seek.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_proc_seek(const long offset, void *const user)
+{
+ struct bin_proc *const p = user;
+
+ return caio_seek(p->caio, offset) ? NW_FATAL : NW_OK;
+}
diff --git a/src/bin/src/proc/stack/CMakeLists.txt b/src/bin/src/proc/stack/CMakeLists.txt
new file mode 100644
index 0000000..3e50879
--- /dev/null
+++ b/src/bin/src/proc/stack/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ pop.c
+ ptr.c
+ push.c
+ read.c
+ write.c
+)
diff --git a/src/bin/src/proc/stack/pop.c b/src/bin/src/proc/stack/pop.c
new file mode 100644
index 0000000..d6ec9e4
--- /dev/null
+++ b/src/bin/src/proc/stack/pop.c
@@ -0,0 +1,64 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <page.h>
+#include <kprintf.h>
+#include <stddef.h>
+
+int bin_proc_s_pop(void *const dst, size_t n, void *const user)
+{
+ struct bin_proc *const p = user;
+ struct bin_stack *const s = &p->stack;
+ unsigned long addr;
+
+ if (!s->page || n > s->sz)
+ {
+ kprintf("%s: stack underflow\n", p->path);
+ return -1;
+ }
+ else if (s->pi)
+ {
+ const size_t rem = s->n - s->pi;
+
+ if (n > rem)
+ n = rem;
+
+ addr = s->sz - rem;
+ }
+ else
+ addr = s->sz - n;
+
+ const int r = page_read(&s->page, addr, dst, n);
+
+ if (r < 0)
+ return -1;
+ else if (r != n)
+ {
+ s->pi += r;
+ s->n = n;
+ return r;
+ }
+ else if (page_shrink(&s->page, addr))
+ return -1;
+
+ s->sz -= s->n ? s->n : n;
+ s->n = s->pi = 0;
+ return r;
+}
diff --git a/src/bin/src/proc/stack/ptr.c b/src/bin/src/proc/stack/ptr.c
new file mode 100644
index 0000000..b0a8763
--- /dev/null
+++ b/src/bin/src/proc/stack/ptr.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+size_t bin_proc_s_ptr(void *const user)
+{
+ const struct bin_proc *const p = user;
+
+ return p->stack.sz;
+}
diff --git a/src/bin/src/proc/stack/push.c b/src/bin/src/proc/stack/push.c
new file mode 100644
index 0000000..bc68180
--- /dev/null
+++ b/src/bin/src/proc/stack/push.c
@@ -0,0 +1,49 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <page.h>
+#include <kprintf.h>
+#include <stddef.h>
+
+int bin_proc_s_push(const void *const src, const size_t n, void *const user)
+{
+ struct bin_proc *const p = user;
+ struct bin_stack *const s = &p->stack;
+ const size_t max = 8192;
+
+ if (n > max || s->sz > max - n)
+ {
+ kprintf("%s: stack overflow\n", p->path);
+ return -1;
+ }
+
+ const int w = page_write(&s->page, s->sz, src, n);
+
+ if (w < 0)
+ return -1;
+#if 0
+ else if (!w)
+ /* TODO: how to unlock? */
+ return bin_proc_lock(p);
+#endif
+
+ s->sz += w;
+ return w;
+}
diff --git a/src/bin/src/proc/stack/read.c b/src/bin/src/proc/stack/read.c
new file mode 100644
index 0000000..5f4a7ac
--- /dev/null
+++ b/src/bin/src/proc/stack/read.c
@@ -0,0 +1,48 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <kprintf.h>
+#include <page.h>
+#include <stddef.h>
+
+int bin_proc_s_read(const size_t offset, void *const dst, const size_t n,
+ void *const user)
+{
+ struct bin_proc *const p = user;
+ struct bin_stack *const s = &p->stack;
+
+ if (n > s->sz || offset > s->sz - n)
+ {
+ kprintf("%s: out-of-bounds stack access\n", p->path);
+ return -1;
+ }
+
+ const int w = page_read(&s->page, offset, dst, n);
+
+ if (w < 0)
+ return -1;
+#if 0
+ else if (!w)
+ /* TODO: how to unlock? */
+ return bin_proc_lock(p);
+#endif
+
+ return w;
+}
diff --git a/src/bin/src/proc/stack/write.c b/src/bin/src/proc/stack/write.c
new file mode 100644
index 0000000..0df017a
--- /dev/null
+++ b/src/bin/src/proc/stack/write.c
@@ -0,0 +1,48 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <kprintf.h>
+#include <page.h>
+#include <stddef.h>
+
+int bin_proc_s_write(const size_t offset, const void *const dst,
+ const size_t n, void *const user)
+{
+ struct bin_proc *const p = user;
+ struct bin_stack *const s = &p->stack;
+
+ if (n > s->sz || offset > s->sz - n)
+ {
+ kprintf("%s: out-of-bounds stack access\n", p->path);
+ return -1;
+ }
+
+ const int w = page_write(&s->page, offset, dst, n);
+
+ if (w < 0)
+ return -1;
+#if 0
+ else if (!w)
+ /* TODO: how to unlock? */
+ return bin_proc_lock(p);
+#endif
+
+ return w;
+}
diff --git a/src/bin/src/proc/tell.c b/src/bin/src/proc/tell.c
new file mode 100644
index 0000000..ed12896
--- /dev/null
+++ b/src/bin/src/proc/tell.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_proc_tell(long *const offset, void *const user)
+{
+ const struct bin_proc *const p = user;
+ off_t off;
+
+ if (caio_tell(p->caio, &off))
+ return NW_FATAL;
+
+ *offset = off;
+ return NW_OK;
+}
diff --git a/src/bin/src/proc/unlock.c b/src/bin/src/proc/unlock.c
new file mode 100644
index 0000000..101b093
--- /dev/null
+++ b/src/bin/src/proc/unlock.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <stddef.h>
+
+int bin_proc_unlock(struct bin_proc *const p)
+{
+ return bin_proc_move(p, &bin_locked, &bin_active);
+}
diff --git a/src/bin/src/start.c b/src/bin/src/start.c
new file mode 100644
index 0000000..dc98e7f
--- /dev/null
+++ b/src/bin/src/start.c
@@ -0,0 +1,127 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+#include <stdlib.h>
+
+static void add_proc(struct bin_proc *const pr)
+{
+ struct bin *const p = &bin_pending, *const a = &bin_active;
+
+ if (p->proc_head == pr)
+ p->proc_head = pr->next;
+
+ if (p->proc_tail == pr)
+ p->proc_tail = pr->prev;
+
+ if (pr->next)
+ pr->next->prev = pr->prev;
+
+ if (pr->prev)
+ pr->prev->next = pr->next;
+
+ if (!a->proc_head)
+ a->proc_head = pr;
+ else
+ {
+ struct bin_proc *const t = a->proc_tail;
+
+ t->next = pr;
+ pr->prev = t;
+ pr->next = NULL;
+ }
+
+ a->proc_tail = pr;
+}
+
+static void move_mod(struct bin_mod *const m)
+{
+ struct bin *const p = &bin_pending, *const a = &bin_active;
+
+ if (p->mod_head == m)
+ p->mod_head = m->next;
+
+ if (p->mod_tail == m)
+ p->mod_tail = m->prev;
+
+ if (m->next)
+ m->next->prev = m->prev;
+
+ if (m->prev)
+ m->prev->next = m->next;
+
+ if (!a->mod_head)
+ a->mod_head = m;
+ else
+ {
+ struct bin_mod *const t = a->mod_tail;
+
+ t->next = m;
+ m->prev = t;
+ m->next = NULL;
+ }
+
+ a->mod_tail = m;
+}
+
+static int setup_mems(struct bin_proc *const p)
+{
+ const struct nw_mod_out *const mout = &p->mod->mod_out;
+ const size_t n = mout->global;
+ void *const gl = malloc(n);
+
+ if (!gl)
+ return -1;
+
+ p->global = (const struct bin_global)
+ {
+ .buf = gl,
+ .sz = n
+ };
+
+ return 0;
+}
+
+int bin_start(struct bin_mod *const m)
+{
+ int ret = -1;
+ struct bin *const b = &bin_pending;
+
+ for (struct bin_proc *p = b->proc_head; p;)
+ {
+ struct bin_proc *const next = p->next;
+
+ if (p->mod == m)
+ {
+ if (setup_mems(p))
+ return -1;
+
+ add_proc(p);
+ ret = 0;
+ }
+
+ p = next;
+ }
+
+ if (!ret)
+ move_mod(m);
+
+ return ret;
+}
diff --git a/src/bin/src/stop.c b/src/bin/src/stop.c
new file mode 100644
index 0000000..978da81
--- /dev/null
+++ b/src/bin/src/stop.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/proc.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+
+int bin_stop(struct bin_proc *const p)
+{
+ return bin_proc_move(p, &bin_active, &bin_zombie);
+}
diff --git a/src/bin/src/update.c b/src/bin/src/update.c
new file mode 100644
index 0000000..3f03ae7
--- /dev/null
+++ b/src/bin/src/update.c
@@ -0,0 +1,145 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/mod.h>
+#include <bin/proc.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+#include <kprintf.h>
+#include <nanowasm/nw.h>
+#include <stdbool.h>
+
+static int load(void)
+{
+ struct bin *const b = &bin_pending;
+
+ for (struct bin_mod *m = b->mod_head; m;)
+ {
+ struct bin_mod *const next = m->next;
+
+ switch (nw_load(&m->mod, &m->mod_out))
+ {
+ case STATE_AGAIN:
+ break;
+
+ case STATE_FATAL:
+ /* TODO: call nw_loadexc. */
+ kprintf("Module %s failed to load\n", m->path);
+
+ if (bin_unload(m))
+ kprintf("Failed to unload module %s\n", m->path);
+
+ bin_mod_free(m);
+ break;
+
+ case STATE_OK:
+ kprintf("Module %s loaded successfully\n", m->path);
+
+ if (bin_start(m))
+ return -1;
+
+ break;
+ }
+
+ m = next;
+ }
+
+ return 0;
+}
+
+static int run(void)
+{
+ for (struct bin_proc *p = bin_active.proc_head; p;)
+ {
+ struct bin_proc *const next = p->next;
+ struct nw_inst *const i = &p->instance;
+
+ switch (nw_run(i))
+ {
+ case STATE_AGAIN:
+ break;
+
+ case STATE_FATAL:
+ kprintf("Instance %s failed to run: %s\n", p->path, nw_rexc(i));
+
+ if (bin_stop(p))
+ kprintf("Failed to stop instance %s\n", p->path);
+
+ break;
+
+ case STATE_OK:
+ /* TODO: remove from queue. */
+ break;
+ }
+
+ p = next;
+ }
+
+ return 0;
+}
+
+static int prune(const struct bin_mod *const mod)
+{
+ for (struct bin_mod *m = bin_active.mod_head; m;)
+ {
+ struct bin_mod *const next = m->next;
+
+ if (m == mod)
+ {
+ if (bin_mod_move(m, &bin_active, NULL))
+ return -1;
+
+ bin_mod_free(m);
+ break;
+ }
+
+ m = next;
+ }
+
+ return 0;
+}
+
+static int kill(void)
+{
+ for (struct bin_proc *p = bin_zombie.proc_head; p;)
+ {
+ struct bin_proc *const next = p->next;
+ const struct bin_mod *const mod = p->mod;
+ bool used = false;
+
+ kprintf("%s exited with status %ld\n", p->path, p->retval);
+
+ if (bin_proc_move(p, &bin_zombie, NULL))
+ return -1;
+
+ bin_proc_free(p);
+
+ if (!used && prune(mod))
+ return -1;
+
+ p = next;
+ }
+
+ return 0;
+}
+
+int bin_update(void)
+{
+ return load() || run() || kill();
+}
diff --git a/src/bin/src/wnix/CMakeLists.txt b/src/bin/src/wnix/CMakeLists.txt
new file mode 100644
index 0000000..b4868f2
--- /dev/null
+++ b/src/bin/src/wnix/CMakeLists.txt
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(bin PRIVATE
+ argc.c
+ argcopy.c
+ arglen.c
+ exit.c
+ mkdir.c
+ mount.c
+ set_errno.c
+)
diff --git a/src/bin/src/wnix/argc.c b/src/bin/src/wnix/argc.c
new file mode 100644
index 0000000..f6d4217
--- /dev/null
+++ b/src/bin/src/wnix/argc.c
@@ -0,0 +1,33 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_wnix_argc(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ const struct bin_proc *const p = user;
+
+ ret->i32 = p->argc;
+ return NW_OK;
+}
diff --git a/src/bin/src/wnix/argcopy.c b/src/bin/src/wnix/argcopy.c
new file mode 100644
index 0000000..cedb26e
--- /dev/null
+++ b/src/bin/src/wnix/argcopy.c
@@ -0,0 +1,143 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/wnix/routines.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <endian.h>
+#include <nanowasm/nw.h>
+#include <nanowasm/linear.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct argcopy
+{
+ long arg;
+ unsigned long addr, errno_addr;
+ union nw_value *ret;
+ size_t read;
+};
+
+static void free_argcopy(struct argcopy *const c)
+{
+ if (!c)
+ return;
+
+ free(c);
+}
+
+static enum nw_state errno_set(void *const user,
+ struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct argcopy *const c = p->import;
+
+ c->ret->i32 = -1;
+ free_argcopy(c);
+ return NW_OK;
+}
+
+static int set_errno(struct bin_proc *const p, const int error,
+ struct nw_next *const next)
+{
+ struct argcopy *const c = p->import;
+
+ *next = (const struct nw_next)
+ {
+ .fn = errno_set,
+ .user = p
+ };
+
+ return bin_wnix_set_errno(p, error, c->errno_addr, next);
+}
+
+static enum nw_state read_arg(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct argcopy *const c = p->import;
+ const char *const arg = p->argv[c->arg];
+ const unsigned long addr = c->addr + c->read;
+ char b = arg[c->read];
+ struct nw_sm_io io = {.buf = &b, .n = sizeof b};
+ const enum nw_state n = nw_linear_store(&p->instance, &io, addr);
+
+ if (n)
+ return n;
+ else if (++c->read >= strlen(arg) + 1)
+ {
+ c->ret->i32 = 0;
+ free_argcopy(c);
+ return NW_OK;
+ }
+
+ return NW_AGAIN;
+}
+
+static enum nw_state check(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct argcopy *const c = p->import;
+
+ if (c->arg < 0 || c->arg >= p->argc || !c->addr || !c->errno_addr)
+ {
+ if (c->errno_addr)
+ {
+ if (set_errno(p, EINVAL, next))
+ goto failure;
+ }
+ else
+ {
+ c->ret->i32 = -1;
+ return NW_OK;
+ }
+ }
+ else
+ *next = (const struct nw_next){.fn = read_arg, .user = user};
+
+failure:
+ free_argcopy(c);
+ return NW_FATAL;
+}
+
+enum nw_state bin_wnix_argcopy(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ enum {ARG, ADDR, ERRNO};
+ struct argcopy *const c = malloc(sizeof *c);
+
+ if (!c)
+ return NW_FATAL;
+
+ *c = (const struct argcopy)
+ {
+ .arg = params[ARG].i32,
+ .addr = params[ADDR].i32,
+ .errno_addr = params[ERRNO].i32,
+ .ret = ret
+ };
+
+ struct bin_proc *const p = user;
+
+ *next = (const struct nw_next){.fn = check, .user = user};
+ p->import = c;
+ return NW_AGAIN;
+}
diff --git a/src/bin/src/wnix/arglen.c b/src/bin/src/wnix/arglen.c
new file mode 100644
index 0000000..b16c4eb
--- /dev/null
+++ b/src/bin/src/wnix/arglen.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+#include <string.h>
+
+enum nw_state bin_wnix_arglen(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ const struct bin_proc *const p = user;
+ const long arg = params->i32;
+
+ if (arg < 0 || arg >= p->argc)
+ ret->i32 = 0;
+ else
+ ret->i32 = strlen(p->argv[arg]);
+
+ return NW_OK;
+}
diff --git a/src/bin/src/wnix/exit.c b/src/bin/src/wnix/exit.c
new file mode 100644
index 0000000..8540250
--- /dev/null
+++ b/src/bin/src/wnix/exit.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/proc.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+#include <nanowasm/nw.h>
+
+enum nw_state bin_wnix_exit(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+
+ if (bin_stop(p))
+ return NW_FATAL;
+
+ p->retval = params->i32;
+ return NW_OK;
+}
diff --git a/src/bin/src/wnix/mkdir.c b/src/bin/src/wnix/mkdir.c
new file mode 100644
index 0000000..30a274a
--- /dev/null
+++ b/src/bin/src/wnix/mkdir.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/wnix/routines.h>
+#include <bin/proc.h>
+#include <bin/types.h>
+#include <endian.h>
+#include <nanowasm/nw.h>
+#include <nanowasm/linear.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum nw_state bin_wnix_mkdir(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ /* TODO */
+ ret->i32 = -1;
+ return NW_OK;
+}
diff --git a/src/bin/src/wnix/mount.c b/src/bin/src/wnix/mount.c
new file mode 100644
index 0000000..562f7d9
--- /dev/null
+++ b/src/bin/src/wnix/mount.c
@@ -0,0 +1,298 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/wnix.h>
+#include <bin/proc.h>
+#include <bin/routines.h>
+#include <bin/types.h>
+#include <bin/wnix/routines.h>
+#include <aio.h>
+#include <endian.h>
+#include <state.h>
+#include <nanowasm/nw.h>
+#include <nanowasm/linear.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct mount
+{
+ struct mountstr
+ {
+ unsigned long addr;
+ char *str;
+ } src, tgt, type;
+
+ unsigned long flags, args, errno_addr;
+ struct endian_le32 le32;
+ union nw_value *ret;
+ struct nw_sm_io io;
+ enum state state;
+ struct aio *aio;
+ int error;
+ size_t i;
+};
+
+static void free_mount(struct mount *const m)
+{
+ aio_free(m->aio);
+ free(m->src.str);
+ free(m->tgt.str);
+ free(m->type.str);
+ free(m);
+}
+
+static enum nw_state errno_set(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mount *const m = p->import;
+
+ m->ret->i32 = -1;
+ free_mount(m);
+ return NW_OK;
+}
+
+static int set_errno(struct bin_proc *const p, const int error,
+ struct nw_next *const next)
+{
+ struct mount *const m = p->import;
+
+ *next = (const struct nw_next)
+ {
+ .fn = errno_set,
+ .user = p
+ };
+
+ return bin_wnix_set_errno(p, error, m->errno_addr, next);
+}
+
+static enum nw_state mounted(void *const user, struct nw_next *const next)
+{
+ enum nw_state ret = NW_FATAL;
+ struct bin_proc *const p = user;
+ struct mount *const m = p->import;
+
+ if (m->state)
+ {
+ if (set_errno(p, m->error, next))
+ goto end;
+
+ return NW_AGAIN;
+ }
+
+ m->ret->i32 = 0;
+ ret = NW_OK;
+end:
+ free_mount(m);
+ return ret;
+}
+
+static int done(const enum state state, void *const args)
+{
+ struct bin_proc *const p = args;
+ struct mount *const m = p->import;
+
+ if (bin_proc_unlock(p))
+ {
+ free_mount(m);
+ return -1;
+ }
+ else if (state)
+ m->error = errno;
+
+ m->state = state;
+ return 0;
+}
+
+static enum nw_state do_mount(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mount *const m = p->import;
+ const struct aio_mount am =
+ {
+ .type = m->type.str,
+ .mount =
+ {
+ .src = m->src.str,
+ .tgt = m->tgt.str,
+ .mode = m->flags,
+ .gid = p->gid,
+ .uid = p->uid
+ }
+ };
+
+ const struct aio_done d =
+ {
+ .f = done,
+ .args = p
+ };
+
+ if (!(m->aio = aio_mount(&am, &d)))
+ {
+ if (set_errno(p, errno, next))
+ goto failure;
+
+ return NW_AGAIN;
+ }
+ else if (bin_proc_lock(p))
+ goto failure;
+
+ *next = (const struct nw_next){.fn = mounted, .user = p};
+ return NW_OK;
+
+failure:
+ free_mount(m);
+ return NW_FATAL;
+}
+
+static enum nw_state read_str(struct bin_proc *const p,
+ struct mountstr *const ms)
+{
+ char b;
+ struct mount *const m = p->import;
+ struct nw_sm_io io = {.buf = &b, .n = sizeof b};
+ const enum nw_state n = nw_linear_load(&p->instance, &io, ms->addr + m->i);
+
+ if (n)
+ return n;
+
+ char *const s = realloc(ms->str, m->i + 1);
+
+ if (!s)
+ return NW_FATAL;
+
+ s[m->i++] = b;
+ ms->str = s;
+ return b ? NW_AGAIN : NW_OK;
+}
+
+static enum nw_state check_read_str(struct bin_proc *const p,
+ struct mountstr *const ms, const struct nw_next *const innext,
+ struct nw_next *const outnext)
+{
+ struct mount *const m = p->import;
+ enum {PATHMAX = 128};
+
+ if (m->i >= PATHMAX)
+ {
+ free_mount(m);
+ /* TODO: assign errno. */
+ m->ret->i32 = -1;
+ return NW_OK;
+ }
+
+ switch (read_str(p, ms))
+ {
+ case NW_FATAL:
+ free_mount(m);
+ return NW_FATAL;
+
+ case NW_OK:
+ m->i = 0;
+ *outnext = *innext;
+ break;
+
+ case NW_AGAIN:
+ break;
+ }
+
+ return NW_AGAIN;
+}
+
+static enum nw_state read_type(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mount *const m = p->import;
+ const struct nw_next rnext = {.fn = do_mount, .user = p};
+
+ return check_read_str(p, &m->type, &rnext, next);
+}
+
+static enum nw_state read_tgt(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mount *const m = p->import;
+ const struct nw_next rnext = {.fn = read_type, .user = p};
+
+ return check_read_str(p, &m->tgt, &rnext, next);
+}
+
+static enum nw_state read_src(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mount *const m = p->import;
+ const struct nw_next rnext = {.fn = read_tgt, .user = p};
+
+ return check_read_str(p, &m->src, &rnext, next);
+}
+
+static enum nw_state check(void *const user, struct nw_next *const next)
+{
+ struct bin_proc *const p = user;
+ struct mount *const m = p->import;
+
+ if (!m->src.addr || !m->tgt.addr || !m->type.addr || !m->errno_addr)
+ {
+ if (m->errno_addr)
+ {
+ if (set_errno(p, EINVAL, next))
+ goto failure;
+ }
+ else
+ {
+ m->ret->i32 = -1;
+ return NW_OK;
+ }
+ }
+ else
+ *next = (const struct nw_next){.fn = read_src, .user = user};
+
+ return NW_AGAIN;
+
+failure:
+ free_mount(m);
+ return NW_FATAL;
+}
+
+enum nw_state bin_wnix_mount(const union nw_value *const params,
+ union nw_value *const ret, void *const user,
+ struct nw_next *const next)
+{
+ enum {SRC, TGT, TYPE, FLAGS, ARGS, ERRNO};
+ struct mount *const m = malloc(sizeof *m);
+
+ if (!m)
+ return NW_FATAL;
+
+ *m = (const struct mount)
+ {
+ .args = params[ARGS].i32,
+ .flags = params[FLAGS].i32,
+ .type.addr = params[TYPE].i32,
+ .tgt.addr = params[TGT].i32,
+ .src.addr = params[SRC].i32,
+ .errno_addr = params[ERRNO].i32,
+ .ret = ret
+ };
+
+ struct bin_proc *const p = user;
+
+ *next = (const struct nw_next){.fn = check, .user = user};
+ p->import = m;
+ return NW_AGAIN;
+}
diff --git a/src/bin/src/wnix/set_errno.c b/src/bin/src/wnix/set_errno.c
new file mode 100644
index 0000000..cc04420
--- /dev/null
+++ b/src/bin/src/wnix/set_errno.c
@@ -0,0 +1,73 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <bin.h>
+#include <bin/types.h>
+#include <bin/wnix/routines.h>
+#include <endian.h>
+#include <nanowasm/nw.h>
+#include <stdlib.h>
+
+struct set_errno
+{
+ struct bin_proc *p;
+ struct nw_next next;
+ struct nw_sm_io io;
+ struct endian_le32 error;
+ unsigned long addr;
+};
+
+static enum nw_state store_errno(void *const user,
+ struct nw_next *const next)
+{
+ struct set_errno *const e = user;
+ struct bin_proc *const p = e->p;
+ const enum nw_state n = nw_linear_store(&p->instance, &e->io, e->addr);
+
+ if (n)
+ return n;
+
+ *next = e->next;
+ free(e);
+ return NW_AGAIN;
+}
+
+int bin_wnix_set_errno(struct bin_proc *const p, const int error,
+ const unsigned long addr, struct nw_next *const next)
+{
+ struct set_errno *const e = malloc(sizeof *e);
+
+ if (!e)
+ return -1;
+
+ *e = (const struct set_errno)
+ {
+ .error = endian_to_le32(error),
+ .next = *next,
+ .addr = addr,
+ .p = p,
+ .io =
+ {
+ .buf = &e->error,
+ .n = sizeof e->error
+ }
+ };
+
+ *next = (const struct nw_next){.fn = store_errno, .user = e};
+ return 0;
+}
diff --git a/src/caio/CMakeLists.txt b/src/caio/CMakeLists.txt
new file mode 100644
index 0000000..980d21b
--- /dev/null
+++ b/src/caio/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(caio)
+add_subdirectory(src)
+target_include_directories(caio PUBLIC include PRIVATE private_include)
+target_link_libraries(caio PUBLIC aio fs state PRIVATE loop)
+# Even if PRIVATE, there are cyclical dependencies among libraries that
+# make LINK_INTERFACE_MULTIPLICITY to exceed its default value (2).
+set_target_properties(caio PROPERTIES LINK_INTERFACE_MULTIPLICITY 3)
diff --git a/src/caio/include/caio.h b/src/caio/include/caio.h
new file mode 100644
index 0000000..284224a
--- /dev/null
+++ b/src/caio/include/caio.h
@@ -0,0 +1,43 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAIO_H
+#define CAIO_H
+
+#include <aio.h>
+#include <stddef.h>
+
+struct caio_open
+{
+ const char *path;
+ int flags;
+ uid_t uid;
+ gid_t gid;
+};
+
+struct caio *caio_open(const struct caio_open *op, const struct aio_done *d);
+int caio_set_caches(struct caio *a, size_t n);
+int caio_read(struct caio *a, void *buf, size_t n, const struct aio_done *d);
+int caio_write(struct caio *a, const void *buf, size_t n,
+ const struct aio_done *d);
+int caio_seek(struct caio *a, off_t offset);
+int caio_tell(const struct caio *a, off_t *offset);
+int caio_eof(const struct caio *a);
+int caio_close(struct caio *a);
+
+#endif
diff --git a/src/caio/private_include/caio/routines.h b/src/caio/private_include/caio/routines.h
new file mode 100644
index 0000000..a83043a
--- /dev/null
+++ b/src/caio/private_include/caio/routines.h
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAIO_ROUTINES_H
+#define CAIO_ROUTINES_H
+
+#include <caio/types.h>
+#include <sys/types.h>
+
+struct caio_cache *caio_cache(struct caio *a);
+
+#endif
diff --git a/src/caio/private_include/caio/types.h b/src/caio/private_include/caio/types.h
new file mode 100644
index 0000000..001a4d3
--- /dev/null
+++ b/src/caio/private_include/caio/types.h
@@ -0,0 +1,46 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAIO_TYPES_H
+#define CAIO_TYPES_H
+
+#include <caio.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct caio_cache
+{
+ off_t offset;
+ size_t available;
+ char buf[2048];
+ struct caio_cache *prev, *next;
+};
+
+struct caio
+{
+ struct aio_done done;
+ struct aio *aio;
+ struct fs_fd fd;
+ struct caio_cache *caches;
+ off_t offset;
+};
+
+#endif
diff --git a/src/caio/src/CMakeLists.txt b/src/caio/src/CMakeLists.txt
new file mode 100644
index 0000000..91b95d4
--- /dev/null
+++ b/src/caio/src/CMakeLists.txt
@@ -0,0 +1,27 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(caio PRIVATE
+ cache.c
+ close.c
+ eof.c
+ open.c
+ read.c
+ seek.c
+ set_caches.c
+ tell.c
+ write.c
+)
diff --git a/src/caio/src/cache.c b/src/caio/src/cache.c
new file mode 100644
index 0000000..edd462c
--- /dev/null
+++ b/src/caio/src/cache.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/routines.h>
+#include <caio/types.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+struct caio_cache *caio_cache(struct caio *const a)
+{
+ for (struct caio_cache *c = a->caches; c; c = c->next)
+ {
+ const off_t offset = a->offset;
+
+ if (c->available
+ && offset >= c->offset
+ && offset < c->offset + sizeof c->buf)
+ return c;
+ }
+
+ return NULL;
+}
diff --git a/src/caio/src/close.c b/src/caio/src/close.c
new file mode 100644
index 0000000..253aaa7
--- /dev/null
+++ b/src/caio/src/close.c
@@ -0,0 +1,44 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/types.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <stdlib.h>
+
+int caio_close(struct caio *const caio)
+{
+ if (!caio)
+ return 0;
+ else
+ aio_free(caio->aio);
+
+ for (struct caio_cache *c = caio->caches; c;)
+ {
+ struct caio_cache *const next = c->next;
+
+ free(c);
+ c = next;
+ }
+
+ aio_close(&caio->fd);
+ free(caio);
+ /* TODO */
+ return -1;
+}
diff --git a/src/caio/src/eof.c b/src/caio/src/eof.c
new file mode 100644
index 0000000..a631546
--- /dev/null
+++ b/src/caio/src/eof.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/types.h>
+
+int caio_eof(const struct caio *const a)
+{
+ return a->offset >= a->fd.size;
+}
diff --git a/src/caio/src/open.c b/src/caio/src/open.c
new file mode 100644
index 0000000..c12432c
--- /dev/null
+++ b/src/caio/src/open.c
@@ -0,0 +1,79 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/types.h>
+#include <aio.h>
+#include <loop.h>
+#include <fs/fs.h>
+#include <stdlib.h>
+
+static int done(const enum state state, void *const args)
+{
+ struct caio *const a = args;
+ const struct aio_done *const d = &a->done;
+
+ if (loop_rm_aio(a->aio))
+ return -1;
+
+ aio_free(a->aio);
+ a->aio = NULL;
+ return d->f ? d->f(state, d->args) : 0;
+}
+
+struct caio *caio_open(const struct caio_open *op,
+ const struct aio_done *const d)
+{
+ struct aio *aio = NULL;
+ struct caio *const ret = malloc(sizeof *ret);
+
+ if (!ret)
+ goto failure;
+
+ const struct fs_open aio_op =
+ {
+ .flags = op->flags,
+ .path = op->path,
+ .uid = op->uid,
+ .gid = op->gid,
+ .fd = &ret->fd,
+ };
+
+ const struct aio_done dd =
+ {
+ .f = done,
+ .args = ret
+ };
+
+ *ret = (const struct caio){0};
+
+ if (caio_set_caches(ret, 1)
+ || !(aio = aio_open(&aio_op, &dd))
+ || loop_add_aio(aio))
+ goto failure;
+ else if (d)
+ ret->done = *d;
+
+ ret->aio = aio;
+ return ret;
+
+failure:
+ aio_free(aio);
+ free(ret);
+ return NULL;
+}
diff --git a/src/caio/src/read.c b/src/caio/src/read.c
new file mode 100644
index 0000000..e1e85b6
--- /dev/null
+++ b/src/caio/src/read.c
@@ -0,0 +1,154 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/routines.h>
+#include <caio/types.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <loop.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int done(const enum state s, void *const args)
+{
+ struct caio *const a = args;
+ const struct aio_done *const d = &a->done;
+
+ if (loop_rm_aio(a->aio))
+ return -1;
+
+ aio_free(a->aio);
+ a->aio = NULL;
+ return d->f ? d->f(s, d->args) : 0;
+}
+
+static size_t read_cache(struct caio *const a, struct caio_cache *const c,
+ void *const buf, size_t n)
+{
+ char *p = buf;
+ size_t i = a->offset % sizeof c->buf;
+
+ while (i < c->available && n)
+ {
+ *p++ = c->buf[i++];
+ n--;
+ }
+
+ const size_t ret = p - (const char *)buf;
+
+ a->offset += ret;
+ return ret;
+}
+
+static size_t getrem(const struct caio *const a)
+{
+ const struct fs_fd *const fd = &a->fd;
+ const off_t n = fd->size - fd->offset;
+ const size_t sz = sizeof a->caches->buf / sizeof *a->caches->buf;
+
+ return n < sz ? n : sz;
+}
+
+static struct caio_cache *rotate(struct caio *const a)
+{
+ const struct fs_fd *const fd = &a->fd;
+ long long maxdiff = LLONG_MAX;
+ struct caio_cache *ret = a->caches;
+
+ for (struct caio_cache *c = a->caches; c; c = c->next)
+ {
+ if (!c->available)
+ return c;
+
+ const long long diff = (long long)c->offset - (long long)fd->offset,
+ adiff = llabs(diff);
+
+ if (adiff < maxdiff)
+ {
+ maxdiff = adiff;
+ ret = c;
+ }
+ }
+
+ return ret;
+}
+
+static int setup_cache(struct caio *const a, const struct aio_done *const d)
+{
+ const size_t rem = getrem(a);
+
+ if (!rem)
+ return 0;
+
+ struct aio *aio = NULL;
+ struct caio_cache *const c = rotate(a);
+ const struct fs_read r =
+ {
+ .fd = &a->fd,
+ .buf = c->buf,
+ .n = rem
+ };
+
+ const struct aio_done dd =
+ {
+ .f = done,
+ .args = a
+ };
+
+ const off_t offset = (a->offset / sizeof c->buf) * sizeof c->buf;
+
+ a->fd.offset = offset;
+
+ if (!(aio = aio_read(&r, &dd)) || loop_add_aio(aio))
+ goto failure;
+ else if (d)
+ a->done = *d;
+ else
+ a->done = (const struct aio_done){0};
+
+ a->aio = aio;
+ c->offset = offset;
+ c->available = rem;
+ return 0;
+
+failure:
+ aio_free(aio);
+ return -1;
+}
+
+int caio_read(struct caio *const a, void *const buf, const size_t n,
+ const struct aio_done *const d)
+{
+ if (a->offset >= a->fd.size)
+ return 0;
+
+ struct caio_cache *const c = caio_cache(a);
+
+ if (c)
+ {
+ const size_t cr = read_cache(a, c, buf, n);
+
+ if (cr)
+ return cr;
+ }
+
+ return setup_cache(a, d);
+}
diff --git a/src/caio/src/readdebugmsg.c b/src/caio/src/readdebugmsg.c
new file mode 100644
index 0000000..11493ba
--- /dev/null
+++ b/src/caio/src/readdebugmsg.c
@@ -0,0 +1,170 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/routines.h>
+#include <caio/types.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <loop.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <drv/ps1/bios.h>
+static int done(const enum state s, void *const args)
+{
+ struct caio *const a = args;
+ const struct aio_done *const d = &a->done;
+
+ if (loop_rm_aio(a->aio))
+ return -1;
+
+ aio_free(a->aio);
+ a->aio = NULL;
+ Printf("finished preparing cache\n");
+ return d->f ? d->f(s, d->args) : 0;
+}
+
+static size_t read_cache(struct caio *const a, struct caio_cache *const c,
+ void *const buf, size_t n)
+{
+ char *p = buf;
+ size_t i = a->offset % sizeof c->buf, start = i;
+ unsigned char checksum = 0;
+
+ while (i < c->available && n)
+ {
+ const unsigned char b = c->buf[i++];
+
+ *p++ = b;
+ checksum += b;
+ n--;
+ }
+
+ const size_t ret = p - (const char *)buf;
+
+ if (ret)
+ Printf("%s: read %lu bytes from cache %p (offset=%lu, bytes [%lu-%lu], chk=%#x)\n",
+ __func__, (unsigned long)ret, (void *)c,
+ (unsigned long)a->offset, (unsigned long)start, (unsigned long)i - 1,
+ (unsigned)checksum);
+
+ a->offset += ret;
+ return ret;
+}
+
+static size_t getrem(const struct caio *const a)
+{
+ const struct fs_fd *const fd = &a->fd;
+ const off_t n = fd->size - fd->offset;
+ const size_t sz = sizeof a->caches->buf / sizeof *a->caches->buf;
+
+ return n < sz ? n : sz;
+}
+
+static struct caio_cache *rotate(struct caio *const a)
+{
+ const struct fs_fd *const fd = &a->fd;
+ long long maxdiff = LLONG_MAX;
+ struct caio_cache *ret = a->caches;
+
+ for (struct caio_cache *c = a->caches; c; c = c->next)
+ {
+ if (!c->available)
+ return c;
+
+ const long long diff = (long long)c->offset - (long long)fd->offset,
+ adiff = llabs(diff);
+
+ if (adiff < maxdiff)
+ {
+ maxdiff = adiff;
+ ret = c;
+ }
+ }
+
+ return ret;
+}
+
+static int setup_cache(struct caio *const a, const struct aio_done *const d)
+{
+ const size_t rem = getrem(a);
+
+ if (!rem)
+ return 0;
+
+ struct aio *aio = NULL;
+ struct caio_cache *const c = rotate(a);
+ const struct fs_read r =
+ {
+ .fd = &a->fd,
+ .buf = c->buf,
+ .n = rem
+ };
+
+ const struct aio_done dd =
+ {
+ .f = done,
+ .args = a
+ };
+
+ const off_t offset = (a->offset / sizeof c->buf) * sizeof c->buf;
+
+ a->fd.offset = offset;
+
+ if (!(aio = aio_read(&r, &dd)) || loop_add_aio(aio))
+ goto failure;
+ else if (d)
+ a->done = *d;
+ else
+ a->done = (const struct aio_done){0};
+
+ a->aio = aio;
+ c->offset = offset;
+ c->available = rem;
+ Printf("%s: setting up cache %p with offset %lu, fd->offset=%lu and %lu bytes\n",
+ __func__, (void *)c, (unsigned long)c->offset, (unsigned long)a->fd.offset,
+ (unsigned long)c->available);
+ return 0;
+
+failure:
+ aio_free(aio);
+ return -1;
+}
+
+int caio_read(struct caio *const a, void *const buf, const size_t n,
+ const struct aio_done *const d)
+{
+ if (a->offset >= a->fd.size)
+ return 0;
+
+ struct caio_cache *const c = caio_cache(a);
+
+ if (c)
+ {
+ const size_t cr = read_cache(a, c, buf, n);
+
+ if (cr)
+ return cr;
+ }
+
+ return setup_cache(a, d);
+}
diff --git a/src/caio/src/readnodebug.c b/src/caio/src/readnodebug.c
new file mode 100644
index 0000000..ed8187e
--- /dev/null
+++ b/src/caio/src/readnodebug.c
@@ -0,0 +1,152 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/routines.h>
+#include <caio/types.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <loop.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int done(const enum state s, void *const args)
+{
+ struct caio *const a = args;
+ const struct aio_done *const d = &a->done;
+
+ if (loop_rm_aio(a->aio))
+ return -1;
+
+ aio_free(a->aio);
+ a->aio = NULL;
+ return d->f ? d->f(s, d->args) : 0;
+}
+
+static size_t read_cache(struct caio *const a, struct caio_cache *const c,
+ void *const buf, size_t n)
+{
+ char *p = buf;
+ size_t i = a->offset % sizeof c->buf;
+
+ while (i < c->available && n)
+ {
+ *p++ = c->buf[i++];
+ n--;
+ }
+
+ const size_t ret = p - (const char *)buf;
+
+ a->offset += ret;
+ return ret;
+}
+
+static size_t getrem(const struct caio *const a)
+{
+ const struct fs_fd *const fd = &a->fd;
+ const off_t n = fd->size - fd->offset;
+ const size_t sz = sizeof a->caches->buf / sizeof *a->caches->buf;
+
+ return n < sz ? n : sz;
+}
+
+static struct caio_cache *rotate(struct caio *const a)
+{
+ const struct fs_fd *const fd = &a->fd;
+ long long maxdiff = LLONG_MAX;
+ struct caio_cache *ret = a->caches;
+
+ for (struct caio_cache *c = a->caches; c; c = c->next)
+ {
+ const long long diff = c->available ?
+ (long long)c->offset - (long long)fd->offset : 0,
+ adiff = llabs(diff);
+
+ if (adiff < maxdiff)
+ {
+ maxdiff = adiff;
+ ret = c;
+ }
+ }
+
+ return ret;
+}
+
+static int setup_cache(struct caio *const a, const struct aio_done *const d)
+{
+ const size_t rem = getrem(a);
+
+ if (!rem)
+ return 0;
+
+ struct aio *aio = NULL;
+ struct caio_cache *const c = rotate(a);
+ const struct fs_read r =
+ {
+ .fd = &a->fd,
+ .buf = c->buf,
+ .n = rem
+ };
+
+ const struct aio_done dd =
+ {
+ .f = done,
+ .args = a
+ };
+
+ const off_t offset = (a->offset / sizeof c->buf) * sizeof c->buf;
+
+ a->fd.offset = offset;
+
+ if (!(aio = aio_read(&r, &dd)) || loop_add_aio(aio))
+ goto failure;
+ else if (d)
+ a->done = *d;
+ else
+ a->done = (const struct aio_done){0};
+
+ a->aio = aio;
+ c->offset = offset;
+ c->available = rem;
+ return 0;
+
+failure:
+ aio_free(aio);
+ return -1;
+}
+
+int caio_read(struct caio *const a, void *const buf, const size_t n,
+ const struct aio_done *const d)
+{
+ if (a->offset >= a->fd.size)
+ return 0;
+
+ struct caio_cache *const c = caio_cache(a);
+
+ if (c)
+ {
+ const size_t cr = read_cache(a, c, buf, n);
+
+ if (cr)
+ return cr;
+ }
+
+ return setup_cache(a, d);
+}
diff --git a/src/caio/src/seek.c b/src/caio/src/seek.c
new file mode 100644
index 0000000..1c0848d
--- /dev/null
+++ b/src/caio/src/seek.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/routines.h>
+#include <caio/types.h>
+#include <sys/types.h>
+
+int caio_seek(struct caio *const a, const off_t offset)
+{
+ struct fs_fd *const fd = &a->fd;
+ const off_t page = offset / sizeof a->caches->buf;
+
+ a->offset = offset;
+
+ if (!caio_cache(a))
+ fd->offset = page * sizeof a->caches->buf;
+
+ return 0;
+}
diff --git a/src/caio/src/set_caches.c b/src/caio/src/set_caches.c
new file mode 100644
index 0000000..dfdd562
--- /dev/null
+++ b/src/caio/src/set_caches.c
@@ -0,0 +1,78 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/types.h>
+#include <errno.h>
+#include <stdlib.h>
+
+int caio_set_caches(struct caio *const a, const size_t n)
+{
+ struct caio_cache *c, *prev = NULL;
+ size_t i;
+
+ if (!n)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (i = 0, c = a->caches; i < n; i++)
+ {
+ if (!c)
+ {
+ struct caio_cache *const nc = malloc(sizeof *nc);
+
+ if (!nc)
+ return -1;
+
+ *nc = (const struct caio_cache){0};
+
+ if (!a->caches)
+ a->caches = nc;
+ else if (prev)
+ {
+ prev->next = nc;
+ nc->prev = prev;
+ }
+
+ prev = nc;
+ }
+ else
+ {
+ prev = c;
+ c = c->next;
+ }
+ }
+
+ for (i = 0, c = a->caches; c; i++)
+ {
+ struct caio_cache *const next = c->next;
+
+ if (i >= n)
+ {
+ c->prev = c->next;
+ c->next = c->prev;
+ free(c);
+ }
+
+ c = next;
+ }
+
+ return 0;
+}
diff --git a/src/caio/src/tell.c b/src/caio/src/tell.c
new file mode 100644
index 0000000..7bfb63a
--- /dev/null
+++ b/src/caio/src/tell.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/types.h>
+
+int caio_tell(const struct caio *const a, off_t *const offset)
+{
+ *offset = a->offset;
+ return 0;
+}
diff --git a/src/caio/src/write.c b/src/caio/src/write.c
new file mode 100644
index 0000000..55ac558
--- /dev/null
+++ b/src/caio/src/write.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <caio.h>
+#include <caio/types.h>
+#include <aio.h>
+#include <fs/fs.h>
+
+int caio_write(struct caio *const caio, const void *const buf, const size_t n,
+ const struct aio_done *d)
+{
+ /* TODO */
+ return -1;
+}
diff --git a/src/drv/CMakeLists.txt b/src/drv/CMakeLists.txt
new file mode 100644
index 0000000..3306d93
--- /dev/null
+++ b/src/drv/CMakeLists.txt
@@ -0,0 +1,28 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv)
+add_subdirectory(event)
+add_subdirectory(tty)
+add_subdirectory(src)
+target_include_directories(drv PUBLIC include PRIVATE private_include)
+target_link_libraries(drv PUBLIC drv_event PRIVATE drv_tty)
+
+if(PS1_BUILD)
+ add_subdirectory(ps1)
+ target_compile_definitions(drv PRIVATE DRV_PS1)
+ target_link_libraries(drv PUBLIC drv_ps1_time PRIVATE drv_ps1)
+endif()
diff --git a/src/drv/event/CMakeLists.txt b/src/drv/event/CMakeLists.txt
new file mode 100644
index 0000000..7d52511
--- /dev/null
+++ b/src/drv/event/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_event INTERFACE)
+target_include_directories(drv_event INTERFACE include)
diff --git a/src/drv/event/include/drv/event.h b/src/drv/event/include/drv/event.h
new file mode 100644
index 0000000..5707242
--- /dev/null
+++ b/src/drv/event/include/drv/event.h
@@ -0,0 +1,49 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_EVENT_H
+#define DRV_EVENT_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct drv_event_done
+{
+ int (*f)(int error, void *args);
+ void *args;
+};
+
+struct drv_event_ops
+{
+ int (*read)(void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done, void *args);
+ int (*read_nb)(void *buf, size_t n, void *args);
+ int (*write)(const void *buf, size_t n, const struct drv_event_done *done,
+ void *args);
+ void *args;
+};
+
+struct drv_event
+{
+ int (*status)(const char *node, const struct drv_event_ops *ops,
+ bool available, mode_t mode, void *args);
+ void *args;
+};
+
+#endif
diff --git a/src/drv/include/drv/drv.h b/src/drv/include/drv/drv.h
new file mode 100644
index 0000000..eb8bee0
--- /dev/null
+++ b/src/drv/include/drv/drv.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_H
+#define DRV_H
+
+#include <drv/event.h>
+
+struct drv *drv_init(const struct drv_event *ev);
+int drv_update(struct drv *d);
+void drv_free(struct drv *d);
+
+#endif
diff --git a/src/drv/include/drv/time.h b/src/drv/include/drv/time.h
new file mode 100644
index 0000000..12b213d
--- /dev/null
+++ b/src/drv/include/drv/time.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TIME_H
+#define DRV_TIME_H
+
+#include <time.h>
+
+int drv_time_getres(clockid_t id, struct timespec *ts);
+int drv_time_gettime(clockid_t id, struct timespec *ts);
+int drv_time_settime(clockid_t id, const struct timespec *ts);
+
+#endif
diff --git a/src/drv/private_include/drv/port.h b/src/drv/private_include/drv/port.h
new file mode 100644
index 0000000..cdf30ab
--- /dev/null
+++ b/src/drv/private_include/drv/port.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PORT_H
+#define DRV_PORT_H
+
+struct drv_port;
+
+#ifdef DRV_PS1
+#include <drv/ps1.h>
+#endif
+
+#endif
diff --git a/src/drv/private_include/drv/tree.h b/src/drv/private_include/drv/tree.h
new file mode 100644
index 0000000..da4b7e9
--- /dev/null
+++ b/src/drv/private_include/drv/tree.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TREE_H
+#define DRV_TREE_H
+
+#include <drv/drv.h>
+#include <drv/port.h>
+#include <stddef.h>
+
+extern struct drv_port *(*const drv_tree_init[])(const struct drv_event *);
+extern int (*const drv_tree_update[])(struct drv_port *);
+extern void (*const drv_tree_free[])(struct drv_port *);
+extern const size_t drv_tree_n;
+
+#endif
diff --git a/src/drv/private_include/drv/types.h b/src/drv/private_include/drv/types.h
new file mode 100644
index 0000000..959e12d
--- /dev/null
+++ b/src/drv/private_include/drv/types.h
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TYPES_H
+#define DRV_TYPES_H
+
+#include <stddef.h>
+
+struct drv
+{
+ struct drv_port **ports;
+ size_t n;
+};
+
+#endif
diff --git a/src/drv/ps1/CMakeLists.txt b/src/drv/ps1/CMakeLists.txt
new file mode 100644
index 0000000..08d97c2
--- /dev/null
+++ b/src/drv/ps1/CMakeLists.txt
@@ -0,0 +1,37 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(bios)
+add_subdirectory(cd)
+add_subdirectory(cpu)
+add_subdirectory(dma)
+add_subdirectory(event)
+add_subdirectory(gpu)
+add_subdirectory(irq)
+add_subdirectory(mc)
+add_subdirectory(pad)
+add_subdirectory(rcnt)
+add_subdirectory(sio)
+add_subdirectory(time)
+add_library(drv_ps1)
+add_subdirectory(src)
+target_include_directories(drv_ps1 PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1 PUBLIC c drv_event PRIVATE
+ drv_ps1_cd
+ drv_ps1_mc
+ drv_ps1_pad
+ drv_ps1_sio
+)
diff --git a/src/drv/ps1/bios/CMakeLists.txt b/src/drv/ps1/bios/CMakeLists.txt
new file mode 100644
index 0000000..ebc0937
--- /dev/null
+++ b/src/drv/ps1/bios/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_bios)
+add_subdirectory(src)
+target_include_directories(drv_ps1_bios INTERFACE include)
diff --git a/src/drv/ps1/bios/include/drv/ps1/bios.h b/src/drv/ps1/bios/include/drv/ps1/bios.h
new file mode 100644
index 0000000..ca53194
--- /dev/null
+++ b/src/drv/ps1/bios/include/drv/ps1/bios.h
@@ -0,0 +1,128 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PS1_BIOS_H
+#define PS1_BIOS_H
+
+#include <stdint.h>
+#include <setjmp.h>
+
+#if __GNUC__
+#define PRINTF_ATTR __attribute__ ((format (__printf__, 1, 2)))
+#else
+#define PRINTF_ATTR
+#endif
+
+enum
+{
+ CLASS_IRQ0 = (long)0xf0000001,
+ CLASS_GPU,
+ CLASS_CDROM,
+ CLASS_DMA,
+ CLASS_RTC0 = (long)0xf2000000,
+ CLASS_RTC1,
+ CLASS_RTC2,
+ CLASS_VBLANK,
+ CLASS_CONTROLLER = (long)0xf0000008,
+ CLASS_SPU,
+ CLASS_PIO,
+ CLASS_SIO
+};
+
+enum
+{
+ MODE_EXECUTE = 0x1000,
+ MODE_READY = 0x2000
+};
+
+enum
+{
+ SPEC_COUNTER_ZERO = 1,
+ SPEC_INTERRUPTED = 1 << 1,
+ SPEC_EOF = 1 << 2,
+ SPEC_FILE_CLOSED = 1 << 3,
+ SPEC_COMMAND_ACK = 1 << 4,
+ SPEC_COMMAND_COMPLETE = 1 << 5,
+ SPEC_DATA_READY = 1 << 6,
+ SPEC_DATA_END = 1 << 7,
+ SPEC_TIMEOUT = 1 << 8,
+ SPEC_UNKNOWN_CMD = 1 << 9,
+ SPEC_END_READ_BUF = 1 << 10,
+ SPEC_END_WRITE_BUF = 1 << 11,
+ SPEC_GENERAL_INTERRUPT = 1 << 12,
+ SPEC_NEW_DEVICE = 1 << 13,
+ SPEC_SYSCALL = 1 << 14,
+ SPEC_ERROR = 1 << 15,
+ SPEC_WRITE_ERROR,
+ SPEC_DOMAIN_ERROR = 0x301,
+ SPEC_RANGE_RNG
+};
+
+struct CdAsyncSeekL
+{
+ uint8_t minutes, seconds, frames;
+};
+
+union SetMode
+{
+ struct
+ {
+ uint8_t cdda :1, autopause :1, report :1, xa_filter :1, ignore :1,
+ whole_sector :1, xa_adpcm :1, speed :1;
+ } bits;
+
+ uint8_t mask;
+};
+
+struct CdAsyncReadSector_mode
+{
+ union SetMode mode;
+ union
+ {
+ struct
+ {
+ uint8_t reads :1, :7;
+ } bits;
+ } read;
+
+ uint16_t reserved;
+};
+
+int EnterCriticalSection(void);
+void ExitCriticalSection(void);
+void GetConf(uint32_t *events, uint32_t *tcb, void **stacktop);
+void SetConf(uint32_t events, uint32_t tcb, void *stacktop);
+int OpenEvent(int class, int spec, int mode, int (*f)(void));
+int EnableEvent(int event);
+int DisableEvent(int event);
+int CloseEvent(int event);
+int TestEvent(int event);
+int WaitEvent(int event);
+int CdAsyncGetStatus(uint8_t *response);
+int CdAsyncReadSector(unsigned count, void *dst,
+ struct CdAsyncReadSector_mode mode);
+int CdAsyncSeekL(const struct CdAsyncSeekL *seekl);
+int Printf(const char *fmt, ...) PRINTF_ATTR;
+void SetCustomExitFromException(jmp_buf jmp);
+void CdInit(void);
+void CdRemove(void);
+int SaveState(jmp_buf buf);
+void RestoreState(jmp_buf buf, int value);
+void ReturnFromException(void);
+
+#endif
diff --git a/src/drv/ps1/bios/src/CMakeLists.txt b/src/drv/ps1/bios/src/CMakeLists.txt
new file mode 100644
index 0000000..67ea62b
--- /dev/null
+++ b/src/drv/ps1/bios/src/CMakeLists.txt
@@ -0,0 +1,38 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_bios PRIVATE
+ CdAsyncGetStatus.s
+ CdAsyncReadSector.s
+ CdAsyncSeekL.s
+ CdInit.s
+ CdRemove.s
+ CloseEvent.s
+ DisableEvent.s
+ EnableEvent.s
+ EnterCriticalSection.s
+ ExitCriticalSection.s
+ GetConf.s
+ OpenEvent.s
+ Printf.s
+ RestoreState.s
+ ReturnFromException.s
+ SaveState.s
+ SetConf.s
+ SetCustomExitFromException.s
+ TestEvent.s
+ WaitEvent.s
+)
diff --git a/src/drv/ps1/bios/src/CdAsyncGetStatus.s b/src/drv/ps1/bios/src/CdAsyncGetStatus.s
new file mode 100644
index 0000000..18922da
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdAsyncGetStatus.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdAsyncGetStatus
+
+CdAsyncGetStatus:
+ li $9, 0x7c
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdAsyncReadSector.s b/src/drv/ps1/bios/src/CdAsyncReadSector.s
new file mode 100644
index 0000000..6411e12
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdAsyncReadSector.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdAsyncReadSector
+
+CdAsyncReadSector:
+ li $9, 0x7e
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdAsyncSeekL.s b/src/drv/ps1/bios/src/CdAsyncSeekL.s
new file mode 100644
index 0000000..529d116
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdAsyncSeekL.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdAsyncSeekL
+
+CdAsyncSeekL:
+ li $9, 0x78
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdInit.s b/src/drv/ps1/bios/src/CdInit.s
new file mode 100644
index 0000000..dcf3474
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdInit.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdInit
+
+CdInit:
+ li $9, 0x54
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CdRemove.s b/src/drv/ps1/bios/src/CdRemove.s
new file mode 100644
index 0000000..e3bb34d
--- /dev/null
+++ b/src/drv/ps1/bios/src/CdRemove.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CdRemove
+
+CdRemove:
+ li $9, 0x56
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/CloseEvent.s b/src/drv/ps1/bios/src/CloseEvent.s
new file mode 100644
index 0000000..7dd47e3
--- /dev/null
+++ b/src/drv/ps1/bios/src/CloseEvent.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global CloseEvent
+
+CloseEvent:
+ li $9, 0x9
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/DisableEvent.s b/src/drv/ps1/bios/src/DisableEvent.s
new file mode 100644
index 0000000..f32dcf8
--- /dev/null
+++ b/src/drv/ps1/bios/src/DisableEvent.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global DisableEvent
+
+DisableEvent:
+ li $9, 0xd
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/EnableEvent.s b/src/drv/ps1/bios/src/EnableEvent.s
new file mode 100644
index 0000000..f6da29d
--- /dev/null
+++ b/src/drv/ps1/bios/src/EnableEvent.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global EnableEvent
+
+EnableEvent:
+ li $9, 0xc
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/EnterCriticalSection.s b/src/drv/ps1/bios/src/EnterCriticalSection.s
new file mode 100644
index 0000000..c8302e0
--- /dev/null
+++ b/src/drv/ps1/bios/src/EnterCriticalSection.s
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global EnterCriticalSection
+
+EnterCriticalSection:
+ li $a0, 1
+ syscall
+ nop
+ jr $ra
+ nop
diff --git a/src/drv/ps1/bios/src/ExitCriticalSection.s b/src/drv/ps1/bios/src/ExitCriticalSection.s
new file mode 100644
index 0000000..198b040
--- /dev/null
+++ b/src/drv/ps1/bios/src/ExitCriticalSection.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global ExitCriticalSection
+
+ExitCriticalSection:
+ li $a0, 2
+ syscall
+ nop
+ jr $ra
+ nop
diff --git a/src/drv/ps1/bios/src/GetConf.s b/src/drv/ps1/bios/src/GetConf.s
new file mode 100644
index 0000000..927b950
--- /dev/null
+++ b/src/drv/ps1/bios/src/GetConf.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global GetConf
+
+GetConf:
+ li $9, 0x9d
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/OpenEvent.s b/src/drv/ps1/bios/src/OpenEvent.s
new file mode 100644
index 0000000..dca7141
--- /dev/null
+++ b/src/drv/ps1/bios/src/OpenEvent.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global OpenEvent
+
+OpenEvent:
+ li $9, 0x8
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/Printf.s b/src/drv/ps1/bios/src/Printf.s
new file mode 100644
index 0000000..9e0a77f
--- /dev/null
+++ b/src/drv/ps1/bios/src/Printf.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global Printf
+
+Printf:
+ li $9, 0x3f
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/RestoreState.s b/src/drv/ps1/bios/src/RestoreState.s
new file mode 100644
index 0000000..c830296
--- /dev/null
+++ b/src/drv/ps1/bios/src/RestoreState.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global RestoreState
+
+RestoreState:
+ li $9, 0x14
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/ReturnFromException.s b/src/drv/ps1/bios/src/ReturnFromException.s
new file mode 100644
index 0000000..6af3bb3
--- /dev/null
+++ b/src/drv/ps1/bios/src/ReturnFromException.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global ReturnFromException
+
+ReturnFromException:
+ li $9, 0x17
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/SaveState.s b/src/drv/ps1/bios/src/SaveState.s
new file mode 100644
index 0000000..eb72ea3
--- /dev/null
+++ b/src/drv/ps1/bios/src/SaveState.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global SaveState
+
+SaveState:
+ li $9, 0x13
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/SetConf.s b/src/drv/ps1/bios/src/SetConf.s
new file mode 100644
index 0000000..5063667
--- /dev/null
+++ b/src/drv/ps1/bios/src/SetConf.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global SetConf
+
+SetConf:
+ li $9, 0x9c
+ j 0xa0
+ nop
diff --git a/src/drv/ps1/bios/src/SetCustomExitFromException.s b/src/drv/ps1/bios/src/SetCustomExitFromException.s
new file mode 100644
index 0000000..75cf8cc
--- /dev/null
+++ b/src/drv/ps1/bios/src/SetCustomExitFromException.s
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.global SetCustomExitFromException
+
+SetCustomExitFromException:
+ li $9, 0x19
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/TestEvent.s b/src/drv/ps1/bios/src/TestEvent.s
new file mode 100644
index 0000000..af0edab
--- /dev/null
+++ b/src/drv/ps1/bios/src/TestEvent.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global TestEvent
+
+TestEvent:
+ li $9, 0xb
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/bios/src/WaitEvent.s b/src/drv/ps1/bios/src/WaitEvent.s
new file mode 100644
index 0000000..8f58d52
--- /dev/null
+++ b/src/drv/ps1/bios/src/WaitEvent.s
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+.text
+
+.global WaitEvent
+
+WaitEvent:
+ li $9, 0xa
+ j 0xb0
+ nop
diff --git a/src/drv/ps1/cd/CMakeLists.txt b/src/drv/ps1/cd/CMakeLists.txt
new file mode 100644
index 0000000..9b84541
--- /dev/null
+++ b/src/drv/ps1/cd/CMakeLists.txt
@@ -0,0 +1,27 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_cd)
+add_subdirectory(src)
+target_include_directories(drv_ps1_cd PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_cd
+ PUBLIC
+ c
+ drv_event
+ PRIVATE
+ drv_ps1_bios
+ drv_ps1_event
+)
diff --git a/src/drv/ps1/cd/include/drv/ps1/cd.h b/src/drv/ps1/cd/include/drv/ps1/cd.h
new file mode 100644
index 0000000..ff57622
--- /dev/null
+++ b/src/drv/ps1/cd/include/drv/ps1/cd.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_H
+#define DRV_PS1_CD_H
+
+#include <drv/event.h>
+
+struct drv_ps1_cd *drv_ps1_cd_init(const struct drv_event *ev);
+int drv_ps1_cd_update(struct drv_ps1_cd *cd);
+void drv_ps1_cd_free(struct drv_ps1_cd *cd);
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h
new file mode 100644
index 0000000..37b2d03
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/regs.h
@@ -0,0 +1,66 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_REGS_H
+#define DRV_PS1_CD_REGS_H
+
+#include <stdint.h>
+
+struct cd_reg_status
+{
+ uint8_t index :2;
+ const uint8_t ADPBUSY :1, PRMEMPT :1, PRMWRDY :1, RSLRRDY :1, DRQSTS :1,
+ BUSYSTS :1;
+};
+
+struct cd_reg_cmd
+{
+ uint8_t cmd;
+};
+
+struct cd_reg_rsp
+{
+ uint8_t rsp;
+};
+
+struct cd_reg_param
+{
+ uint8_t param;
+};
+
+union cd_reg_if
+{
+ const struct
+ {
+ uint8_t response :3, :1, cmd_start :1, :3;
+ } r;
+
+ struct
+ {
+ uint8_t ack: 5, :1, CLRPRM :1, :1;
+ } w;
+};
+
+#define CD_REG(x) (0x1f801800 + (x))
+#define CD_REG_STATUS ((volatile struct cd_reg_status *)CD_REG(0))
+#define CD_REG_CMD ((volatile struct cd_reg_cmd *)CD_REG(1))
+#define CD_REG_RSP ((const volatile struct cd_reg_rsp *)CD_REG(1))
+#define CD_REG_PARAM ((volatile struct cd_reg_param *)CD_REG(2))
+#define CD_REG_IF ((volatile union cd_reg_if *)CD_REG(3))
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h
new file mode 100644
index 0000000..0b756de
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/routines.h
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_ROUTINES_H
+#define DRV_PS1_CD_ROUTINES_H
+
+#include <drv/event.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/bios.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+int drv_ps1_cd_send(const struct cmd *cmd);
+int drv_ps1_cd_getstat(void);
+int drv_ps1_cd_read(void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done, void *args);
+int drv_ps1_cd_write(const void *buf, size_t n,
+ const struct drv_event_done *done, void *args);
+int drv_ps1_cd_next(void);
+struct CdAsyncSeekL drv_ps1_cd_toseekl(unsigned i);
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/types.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/types.h
new file mode 100644
index 0000000..2d4ae51
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/types.h
@@ -0,0 +1,111 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_TYPES_H
+#define DRV_PS1_CD_TYPES_H
+
+#include <drv/event.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+struct drv_ps1_cd
+{
+ bool available;
+ struct drv_event ev;
+};
+
+struct cmd
+{
+ enum
+ {
+ CMD_SYNC,
+ CMD_GETSTAT,
+ CMD_SETLOC,
+ } cmd;
+
+ union cmd_param
+ {
+ struct cmd_setloc
+ {
+ uint8_t min, sec, sect;
+ } setloc;
+ } params;
+};
+
+struct cd_prv_getstat
+{
+ union
+ {
+ struct
+ {
+ uint8_t invalid :1, motor :1, seek_error :1, id_error :1,
+ shell_open :1, reading :1, seeking :1, playing_cdda :1;
+ } bits;
+
+ uint8_t byte;
+ } status;
+};
+
+struct cd_prv_read
+{
+ int endevent, errevent;
+};
+
+struct cd_req_read
+{
+ void *buf;
+ size_t n;
+ off_t offset;
+};
+
+struct cd_req
+{
+ union
+ {
+ struct cd_req_read read;
+ } u;
+
+ int (*f)(void);
+ struct drv_event_done done;
+ struct cd_req *next;
+};
+
+enum {CD_SECTOR_SZ = 2048};
+
+struct cd_prv
+{
+ bool available, sector_read;
+ int (*next)(void);
+ int event;
+ struct cmd cmd;
+ struct cd_req *head, *tail;
+ char sector[CD_SECTOR_SZ];
+ off_t offset;
+
+ union
+ {
+ struct cd_prv_getstat getstat;
+ struct cd_prv_read read;
+ } u;
+};
+
+extern struct cd_prv drv_ps1_cd_prv;
+
+#endif
diff --git a/src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h b/src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h
new file mode 100644
index 0000000..59437c0
--- /dev/null
+++ b/src/drv/ps1/cd/private_include/drv/ps1/cd/virt/types.h
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CD_VIRT_TYPES_H
+#define DRV_PS1_CD_VIRT_TYPES_H
+
+#include <drv/event.h>
+
+struct drv_ps1_cd
+{
+ struct drv_event ev;
+};
+
+struct cd_prv
+{
+ int (*next)(void);
+};
+
+extern struct cd_prv drv_ps1_cd_prv;
+
+#endif
diff --git a/src/drv/ps1/cd/src/CMakeLists.txt b/src/drv/ps1/cd/src/CMakeLists.txt
new file mode 100644
index 0000000..df5ecca
--- /dev/null
+++ b/src/drv/ps1/cd/src/CMakeLists.txt
@@ -0,0 +1,33 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+if(WNIX_VIRT_CD)
+ add_subdirectory(virt)
+else()
+ target_sources(drv_ps1_cd PRIVATE
+ free.c
+ getstat.c
+ init.c
+ next.c
+ prv.c
+ read.c
+ toseekl.c
+ update.c
+ write.c
+ )
+endif()
+
+target_link_libraries(drv_ps1_cd PRIVATE kprintf)
diff --git a/src/drv/ps1/cd/src/ensure_event.c b/src/drv/ps1/cd/src/ensure_event.c
new file mode 100644
index 0000000..592184a
--- /dev/null
+++ b/src/drv/ps1/cd/src/ensure_event.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <stddef.h>
+
+int drv_ps1_cd_ensure_event(struct cd_prv *const p)
+{
+ if (p->event)
+ return 0;
+
+ const int event = drv_ps1_event_open(CLASS_CDROM, SPEC_COMMAND_COMPLETE,
+ MODE_READY, NULL);
+
+ if (event == -1)
+ return -1;
+
+ drv_ps1_event_enable(p->event = event);
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/free.c b/src/drv/ps1/cd/src/free.c
new file mode 100644
index 0000000..ed6f347
--- /dev/null
+++ b/src/drv/ps1/cd/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+
+void drv_ps1_cd_free(struct drv_ps1_cd *const cd)
+{
+}
diff --git a/src/drv/ps1/cd/src/getstat.c b/src/drv/ps1/cd/src/getstat.c
new file mode 100644
index 0000000..34bdaf5
--- /dev/null
+++ b/src/drv/ps1/cd/src/getstat.c
@@ -0,0 +1,70 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/event.h>
+#include <kprintf.h>
+
+static int wait_event(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_getstat *const g = &p->u.getstat;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ p->available = !g->status.bits.shell_open;
+
+ if (!p->head)
+ return drv_ps1_cd_getstat();
+
+ return p->head->f();
+ }
+
+ return 0;
+}
+
+static int ensure_event(struct cd_prv *const p)
+{
+ if (p->event)
+ return 0;
+ else if ((p->event = drv_ps1_event_open(CLASS_CDROM, SPEC_COMMAND_COMPLETE,
+ MODE_READY, NULL)) == -1)
+ return -1;
+
+ drv_ps1_event_enable(p->event);
+ return 0;
+}
+
+int drv_ps1_cd_getstat(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_getstat *const g = &p->u.getstat;
+
+ /* TODO: CdAsyncGetStatus is *very* slow (~2.5 seconds / 10k calls) */
+ if (ensure_event(p))
+ return -1;
+ else if (!CdAsyncGetStatus(&g->status.byte))
+ {
+ kprintf("%s: CdAsyncGetStatus failed\n", __func__);
+ return -1;
+ }
+
+ p->next = wait_event;
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/init.c b/src/drv/ps1/cd/src/init.c
new file mode 100644
index 0000000..b452e82
--- /dev/null
+++ b/src/drv/ps1/cd/src/init.c
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_cd *drv_ps1_cd_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_cd *const ret = malloc(sizeof *ret);
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (!ret)
+ return NULL;
+ else if (!p->next && drv_ps1_cd_getstat())
+ goto failure;
+
+ *ret = (const struct drv_ps1_cd){.ev = *ev};
+ return ret;
+
+failure:
+ free(ret);
+ return NULL;
+}
diff --git a/src/drv/ps1/cd/src/next.c b/src/drv/ps1/cd/src/next.c
new file mode 100644
index 0000000..b26633a
--- /dev/null
+++ b/src/drv/ps1/cd/src/next.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <stdlib.h>
+
+int drv_ps1_cd_next(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_req *const next = p->head->next;
+
+ free(p->head);
+
+ if (next && next->f())
+ return -1;
+ else if (!(p->head = next))
+ return drv_ps1_cd_getstat();
+
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/prv.c b/src/drv/ps1/cd/src/prv.c
new file mode 100644
index 0000000..61ed4b4
--- /dev/null
+++ b/src/drv/ps1/cd/src/prv.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/types.h>
+
+struct cd_prv drv_ps1_cd_prv;
diff --git a/src/drv/ps1/cd/src/read.c b/src/drv/ps1/cd/src/read.c
new file mode 100644
index 0000000..d21cbae
--- /dev/null
+++ b/src/drv/ps1/cd/src/read.c
@@ -0,0 +1,239 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <drv/event.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int seek(void);
+
+static int deliver_event(struct cd_prv *const p, const int error)
+{
+ const struct cd_prv_read *const read = &p->u.read;
+ const struct cd_req *const req = p->head;
+ const struct drv_event_done *const d = &req->done;
+
+ drv_ps1_event_disable(read->endevent);
+ drv_ps1_event_close(read->endevent);
+ drv_ps1_event_disable(read->errevent);
+ drv_ps1_event_close(read->errevent);
+
+ if (!error)
+ {
+ const struct cd_req_read *const rr = &req->u.read;
+ const long offset = rr->offset % CD_SECTOR_SZ;
+
+ memcpy(rr->buf, p->sector + offset, rr->n);
+
+ if (!((p->offset += rr->n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+ }
+
+ if (d->f(error, d->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_read(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_prv_read *const read = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ p->sector_read = true;
+ return deliver_event(p, SUCCESS);
+ }
+ else if (drv_ps1_event_test(read->errevent)
+ || drv_ps1_event_test(read->endevent))
+ return deliver_event(p, EIO);
+
+ return 0;
+}
+
+static int uncached_read(struct cd_prv *const p)
+{
+ int endevent, errevent;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct CdAsyncReadSector_mode mode =
+ {
+ .mode.bits.speed = 1,
+ };
+
+ endevent = drv_ps1_event_open(CLASS_CDROM, SPEC_DATA_END, MODE_READY, NULL);
+ errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR, MODE_READY, NULL);
+
+ if (endevent == -1 || errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read)
+ {
+ .endevent = endevent,
+ .errevent = errevent
+ };
+
+ drv_ps1_event_enable(endevent);
+ drv_ps1_event_enable(errevent);
+
+ if (!CdAsyncReadSector(1, p->sector, mode))
+ goto failure;
+
+ p->next = wait_read;
+ return 0;
+
+failure:
+
+ if (endevent != -1)
+ {
+ drv_ps1_event_disable(endevent);
+ drv_ps1_event_close(endevent);
+ }
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int cached_read(struct cd_prv *const p)
+{
+ struct cd_req *const req = p->head;
+ struct cd_req_read *const rr = &req->u.read;
+ const struct drv_event_done *const done = &req->done;
+ const off_t offset = rr->offset % CD_SECTOR_SZ,
+ rem = CD_SECTOR_SZ - offset,
+ n = rr->n > rem ? rem : rr->n;
+
+ memcpy(rr->buf, p->sector + offset, n);
+
+ if (!((p->offset += n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+
+ if (done->f(SUCCESS, done->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const struct cd_prv_read *const r = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ drv_ps1_event_disable(r->errevent);
+ drv_ps1_event_close(r->errevent);
+ p->offset = rr->offset;
+ return uncached_read(p);
+ }
+ else if (drv_ps1_event_test(r->errevent))
+ return deliver_event(p, EIO);
+
+ return 0;
+}
+
+static int seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct cd_req_read *rr = &p->head->u.read;
+ const unsigned sector = rr->offset / CD_SECTOR_SZ;
+ const struct CdAsyncSeekL seekl = drv_ps1_cd_toseekl(sector);
+ const int errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR,
+ MODE_READY, NULL);
+
+ if (errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read){.errevent = errevent};
+ p->sector_read = false;
+ drv_ps1_event_enable(errevent);
+
+ if (!CdAsyncSeekL(&seekl))
+ goto failure;
+
+ p->next = wait_seek;
+ return 0;
+
+failure:
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int start(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const off_t cursect = p->offset / CD_SECTOR_SZ,
+ tgtsect = rr->offset / CD_SECTOR_SZ;
+
+ if (cursect != tgtsect || !p->sector_read)
+ return seek();
+
+ /* TODO: multi-sector reads, make sure cache can really be used */
+ return cached_read(p);
+}
+
+int drv_ps1_cd_read(void *const buf, const size_t n, const off_t offset,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_req *const r = malloc(sizeof *r);
+
+ if (!r)
+ return -1;
+
+ *r = (const struct cd_req)
+ {
+ .f = start,
+ .done = *done,
+ .u.read =
+ {
+ .offset = offset,
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!p->head)
+ p->head = r;
+ else
+ p->tail->next = r;
+
+ p->tail = r;
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/readdebug b/src/drv/ps1/cd/src/readdebug
new file mode 100644
index 0000000..b2c09a7
--- /dev/null
+++ b/src/drv/ps1/cd/src/readdebug
@@ -0,0 +1,253 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <drv/event.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <drv/ps1/bios.h>
+
+static int seek(void);
+
+static int deliver_event(struct cd_prv *const p, const int error)
+{
+ const struct cd_prv_read *const read = &p->u.read;
+ const struct cd_req *const req = p->head;
+ const struct drv_event_done *const d = &req->done;
+
+ drv_ps1_event_disable(read->endevent);
+ drv_ps1_event_close(read->endevent);
+ drv_ps1_event_disable(read->errevent);
+ drv_ps1_event_close(read->errevent);
+
+ if (!error)
+ {
+ const struct cd_req_read *const rr = &req->u.read;
+ const long offset = rr->offset % CD_SECTOR_SZ;
+
+ memcpy(rr->buf, p->sector + offset, rr->n);
+
+ if (!((p->offset += rr->n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+ }
+
+ if (d->f(error, d->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_read(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_prv_read *const read = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ p->sector_read = true;
+ return deliver_event(p, SUCCESS);
+ }
+ else if (drv_ps1_event_test(read->errevent)
+ || drv_ps1_event_test(read->endevent))
+ return deliver_event(p, EIO);
+
+ return 0;
+}
+
+static int uncached_read(struct cd_prv *const p)
+{
+ int endevent, errevent;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct CdAsyncReadSector_mode mode =
+ {
+ .mode.bits.speed = 1,
+ };
+
+ endevent = drv_ps1_event_open(CLASS_CDROM, SPEC_DATA_END, MODE_READY, NULL);
+ errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR, MODE_READY, NULL);
+
+ if (endevent == -1 || errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read)
+ {
+ .endevent = endevent,
+ .errevent = errevent
+ };
+
+ drv_ps1_event_enable(endevent);
+ drv_ps1_event_enable(errevent);
+
+ Printf("preparing async read\n");
+ if (!CdAsyncReadSector(1, p->sector, mode))
+ goto failure;
+
+ p->next = wait_read;
+ return 0;
+
+failure:
+
+ if (endevent != -1)
+ {
+ drv_ps1_event_disable(endevent);
+ drv_ps1_event_close(endevent);
+ }
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int cached_read(struct cd_prv *const p)
+{
+ struct cd_req *const req = p->head;
+ struct cd_req_read *const rr = &req->u.read;
+ const struct drv_event_done *const done = &req->done;
+ const off_t offset = rr->offset % CD_SECTOR_SZ,
+ rem = CD_SECTOR_SZ - offset,
+ n = rr->n > rem ? rem : rr->n;
+
+ Printf("Doing %lu-byte cached read from offset %lu to %p\n",
+ (unsigned long) n, (unsigned long) offset, (void *)rr->buf);
+ memcpy(rr->buf, p->sector + offset, n);
+
+ if (!((p->offset += n) % CD_SECTOR_SZ))
+ p->sector_read = false;
+
+ if (done->f(SUCCESS, done->args) || drv_ps1_cd_next())
+ return -1;
+
+ return 0;
+}
+
+static int wait_seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const struct cd_prv_read *const r = &p->u.read;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ Printf("finished seeking\n");
+ drv_ps1_event_disable(r->errevent);
+ drv_ps1_event_close(r->errevent);
+ p->offset = rr->offset;
+ return uncached_read(p);
+ }
+ else if (drv_ps1_event_test(r->errevent))
+ {
+ Printf("failed to seek\n");
+ return deliver_event(p, EIO);
+ }
+
+ return 0;
+}
+
+static int seek(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_prv_read *const r = &p->u.read;
+ const struct cd_req_read *rr = &p->head->u.read;
+ const unsigned sector = rr->offset / CD_SECTOR_SZ;
+ const struct CdAsyncSeekL seekl = drv_ps1_cd_toseekl(sector);
+ const int errevent = drv_ps1_event_open(CLASS_CDROM, SPEC_ERROR,
+ MODE_READY, NULL);
+
+ if (errevent == -1)
+ goto failure;
+
+ *r = (const struct cd_prv_read){.errevent = errevent};
+ p->sector_read = false;
+ drv_ps1_event_enable(errevent);
+
+ Printf("Seeking to offset %lu\n", (unsigned long)rr->offset);
+
+ if (!CdAsyncSeekL(&seekl))
+ goto failure;
+
+ p->next = wait_seek;
+ return 0;
+
+failure:
+
+ if (errevent != -1)
+ {
+ drv_ps1_event_disable(errevent);
+ drv_ps1_event_close(errevent);
+ }
+
+ return -1;
+}
+
+static int start(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ const struct cd_req *const req = p->head;
+ const struct cd_req_read *const rr = &req->u.read;
+ const off_t cursect = p->offset / CD_SECTOR_SZ,
+ tgtsect = rr->offset / CD_SECTOR_SZ;
+
+ if (cursect != tgtsect || !p->sector_read)
+ return seek();
+
+ /* TODO: multi-sector reads, make sure cache can really be used */
+ return cached_read(p);
+}
+
+int drv_ps1_cd_read(void *const buf, const size_t n, const off_t offset,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+ struct cd_req *const r = malloc(sizeof *r);
+
+ if (!r)
+ return -1;
+
+ *r = (const struct cd_req)
+ {
+ .f = start,
+ .done = *done,
+ .u.read =
+ {
+ .offset = offset,
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!p->head)
+ p->head = r;
+ else
+ p->tail->next = r;
+
+ p->tail = r;
+ Printf("Added %p {.buf=%p, .n=%lu} to read reqs\n", (void *)p->tail, buf,
+ (unsigned long)n);
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/send.c b/src/drv/ps1/cd/src/send.c
new file mode 100644
index 0000000..01aa5cb
--- /dev/null
+++ b/src/drv/ps1/cd/src/send.c
@@ -0,0 +1,101 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cd/regs.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/event.h>
+#include <stdint.h>
+
+static int wait_event(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (drv_ps1_event_test(p->event))
+ {
+ const union cd_prv_getstat g = {.status = CD_REG_RSP->rsp};
+
+ p->available = !g.bits.shell_open;
+ }
+
+ return 0;
+}
+
+static void send_params(const struct cd_prv *const p)
+{
+ static const size_t n[] =
+ {
+ [CMD_SETLOC] = sizeof (struct cmd_setloc)
+ };
+
+ const uint8_t cmd = p->cmd.cmd, index = CD_REG_STATUS->index;
+
+ if (cmd < sizeof n / sizeof *n)
+ {
+ const void *const vbuf = &p->cmd.params;
+ const uint8_t *buf = vbuf;
+
+ CD_REG_STATUS->index = 0;
+
+ for (size_t i = 0; i < n[cmd]; i++)
+ CD_REG_PARAM->param = *buf++;
+
+ CD_REG_STATUS->index = index;
+ }
+}
+
+static int send_data(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (CD_REG_STATUS->BUSYSTS)
+ return 0;
+
+ send_params(p);
+ CD_REG_CMD->cmd = p->cmd.cmd;
+ p->next = wait_event;
+ return 0;
+}
+
+static int reset_param_fifo(void)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (CD_REG_STATUS->BUSYSTS)
+ return 0;
+
+ CD_REG_IF->w.ack = 0x1f;
+ CD_REG_STATUS->index = 1;
+ CD_REG_IF->w.CLRPRM = 1;
+ p->next = send_data;
+ return 0;
+}
+
+int drv_ps1_cd_send(const struct cmd *const cmd)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (drv_ps1_cd_ensure_event(p))
+ return -1;
+
+ p->cmd = *cmd;
+ p->next = reset_param_fifo;
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/toseekl.c b/src/drv/ps1/cd/src/toseekl.c
new file mode 100644
index 0000000..ee776c9
--- /dev/null
+++ b/src/drv/ps1/cd/src/toseekl.c
@@ -0,0 +1,54 @@
+/* Original functions from psn00bsdk, commit 5d9aa2d3
+ *
+ * itob extracted from libpsn00b/include/psxcd.h
+ * CdIntToPos (here renamed to drv_ps1_cd_toseekl) extracted from
+ * libpsn00b/psxcd/misc.c
+ *
+ * Original copyright notice:
+ *
+ * PSn00bSDK CD-ROM library
+ * (C) 2020-2023 Lameguy64, spicyjpeg - MPL licensed
+ */
+
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/bios.h>
+
+/**
+ * @brief Translates a decimal value to BCD.
+ *
+ * @details Translates a decimal integer in 0-99 range into a BCD format value.
+ */
+static unsigned itob(const unsigned i)
+{
+ return ((i / 10) * 16) | (i % 10);
+}
+
+struct CdAsyncSeekL drv_ps1_cd_toseekl(unsigned i)
+{
+ i += 150;
+
+ return (const struct CdAsyncSeekL)
+ {
+ .minutes = itob(i / (75 * 60)),
+ .seconds = itob((i / 75) % 60),
+ .frames = itob(i % 75)
+ };
+}
diff --git a/src/drv/ps1/cd/src/update.c b/src/drv/ps1/cd/src/update.c
new file mode 100644
index 0000000..148dd87
--- /dev/null
+++ b/src/drv/ps1/cd/src/update.c
@@ -0,0 +1,47 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/event.h>
+#include <stdbool.h>
+
+int drv_ps1_cd_update(struct drv_ps1_cd *const cd)
+{
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (p->next())
+ return -1;
+ else if (p->available ^ cd->available)
+ {
+ const struct drv_event *const ev = &cd->ev;
+ static const struct drv_event_ops ops =
+ {
+ .read = drv_ps1_cd_read,
+ .write = drv_ps1_cd_write
+ };
+
+ if (ev->status("cd0", &ops, p->available, 0440, ev->args))
+ return -1;
+
+ cd->available = p->available;
+ }
+
+ return 0;
+}
diff --git a/src/drv/ps1/cd/src/virt/CMakeLists.txt b/src/drv/ps1/cd/src/virt/CMakeLists.txt
new file mode 100644
index 0000000..0e5bd1b
--- /dev/null
+++ b/src/drv/ps1/cd/src/virt/CMakeLists.txt
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_cd PRIVATE
+ # free.c
+ init.c
+ # next.c
+ # prv.c
+ # read.c
+ # update.c
+ # write.c
+)
diff --git a/src/drv/ps1/cd/src/virt/init.c b/src/drv/ps1/cd/src/virt/init.c
new file mode 100644
index 0000000..204f7fa
--- /dev/null
+++ b/src/drv/ps1/cd/src/virt/init.c
@@ -0,0 +1,41 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/virt/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_cd *drv_ps1_cd_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_cd *const ret = malloc(sizeof *ret);
+ struct cd_prv *const p = &drv_ps1_cd_prv;
+
+ if (!ret)
+ return NULL;
+ else if (!p->next && drv_ps1_cd_getstat())
+ goto failure;
+
+ *ret = (const struct drv_ps1_cd){.ev = *ev};
+ return ret;
+
+failure:
+ free(ret);
+ return NULL;
+}
diff --git a/src/drv/ps1/cd/src/write.c b/src/drv/ps1/cd/src/write.c
new file mode 100644
index 0000000..ba47993
--- /dev/null
+++ b/src/drv/ps1/cd/src/write.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/cd/routines.h>
+#include <drv/ps1/cd/types.h>
+#include <drv/event.h>
+#include <errno.h>
+
+int drv_ps1_cd_write(const void *const buf, const size_t n,
+ const struct drv_event_done *const done, void *const args)
+{
+ /* TODO: write event callback returning EROFS */
+ errno = EROFS;
+ return -1;
+}
diff --git a/src/drv/ps1/cpu/CMakeLists.txt b/src/drv/ps1/cpu/CMakeLists.txt
new file mode 100644
index 0000000..dafb0cd
--- /dev/null
+++ b/src/drv/ps1/cpu/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_cpu INTERFACE)
+target_include_directories(drv_ps1_cpu INTERFACE include)
diff --git a/src/drv/ps1/cpu/include/drv/ps1/cpu.h b/src/drv/ps1/cpu/include/drv/ps1/cpu.h
new file mode 100644
index 0000000..d951f48
--- /dev/null
+++ b/src/drv/ps1/cpu/include/drv/ps1/cpu.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_CPU_H
+#define DRV_PS1_CPU_H
+
+#define DRV_PS1_CPU_F 33868800ul
+
+#endif
diff --git a/src/drv/ps1/dma/CMakeLists.txt b/src/drv/ps1/dma/CMakeLists.txt
new file mode 100644
index 0000000..0daeee9
--- /dev/null
+++ b/src/drv/ps1/dma/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_dma INTERFACE)
+target_include_directories(drv_ps1_dma INTERFACE include)
diff --git a/src/drv/ps1/dma/include/drv/ps1/dma.h b/src/drv/ps1/dma/include/drv/ps1/dma.h
new file mode 100644
index 0000000..9538c3b
--- /dev/null
+++ b/src/drv/ps1/dma/include/drv/ps1/dma.h
@@ -0,0 +1,97 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_DMA_H
+#define DRV_PS1_DMA_H
+
+#include <stdint.h>
+
+union dpcr
+{
+ struct
+ {
+ uint32_t mdecin_prio :3, mdecin_en :1, mdecout_prio :3, mdecout_en :1,
+ gpu_prio :3, gpu_en :1, cdrom_prio :3, cdrom_en :1, spu_prio :3,
+ spu_en :1, pio_prio :3, pio_en :1, otc_prio :3, otc_en :1, :4;
+ } bits;
+
+ uint32_t mask;
+};
+
+union madr
+{
+ struct
+ {
+ uint32_t addr :24, :8;
+ } bits;
+
+ uint32_t mask;
+};
+
+union bcr
+{
+ struct
+ {
+ uint16_t nwords, reserved;
+ } syncmode_0;
+
+ struct
+ {
+ uint16_t blocksz, nblocks;
+ } syncmode_1;
+
+ struct
+ {
+ uint32_t reserved;
+ } syncmode_2;
+
+ uint32_t mask;
+};
+
+enum
+{
+ CHCR_DIR_TO_RAM,
+ CHCR_DIR_FROM_RAM
+};
+
+enum
+{
+ CHCR_SYNC_MODE_ALL,
+ CHCR_SYNC_MODE_BLOCKS,
+ CHCR_SYNC_MODE_LINKED_LIST
+};
+
+union chcr
+{
+ struct
+ {
+ uint32_t dir :1, memstep :1, :6, chopping :1, sync_mode :2, :5,
+ chopping_dma_window_sz :3, :1, chopping_cpu_window_sz :3, :1,
+ start_busy :1, :3, start_trigger :1, :3;
+ } bits;
+
+ uint32_t mask;
+};
+
+#define DMA_BASE(dma, off) ((dma) * 0x10 + 0x1f801080 + (off))
+#define D2_MADR ((volatile union madr *)DMA_BASE(2, 0))
+#define D2_BCR ((volatile union bcr *)DMA_BASE(2, 4))
+#define D2_CHCR ((volatile union chcr *)DMA_BASE(2, 8))
+#define DPCR ((volatile union dpcr *)0x1f8010f0)
+
+#endif
diff --git a/src/drv/ps1/event/CMakeLists.txt b/src/drv/ps1/event/CMakeLists.txt
new file mode 100644
index 0000000..2b00aaa
--- /dev/null
+++ b/src/drv/ps1/event/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_event)
+add_subdirectory(src)
+target_include_directories(drv_ps1_event PUBLIC include)
+target_link_libraries(drv_ps1_event PUBLIC c drv_ps1_bios)
diff --git a/src/drv/ps1/event/include/drv/ps1/event.h b/src/drv/ps1/event/include/drv/ps1/event.h
new file mode 100644
index 0000000..2c34b02
--- /dev/null
+++ b/src/drv/ps1/event/include/drv/ps1/event.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_EVENT_H
+#define DRV_PS1_EVENT_H
+
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_open(int class, int spec, int mode, int (*f)(void));
+int drv_ps1_event_test(int event);
+int drv_ps1_event_wait(int event);
+int drv_ps1_event_enable(int event);
+int drv_ps1_event_disable(int event);
+int drv_ps1_event_close(int event);
+
+#endif
diff --git a/src/drv/ps1/event/src/CMakeLists.txt b/src/drv/ps1/event/src/CMakeLists.txt
new file mode 100644
index 0000000..e741edc
--- /dev/null
+++ b/src/drv/ps1/event/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_event PRIVATE
+ close.c
+ disable.c
+ enable.c
+ open.c
+ test.c
+)
diff --git a/src/drv/ps1/event/src/close.c b/src/drv/ps1/event/src/close.c
new file mode 100644
index 0000000..01c9a33
--- /dev/null
+++ b/src/drv/ps1/event/src/close.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_close(const int event)
+{
+ return CloseEvent(event);
+}
diff --git a/src/drv/ps1/event/src/disable.c b/src/drv/ps1/event/src/disable.c
new file mode 100644
index 0000000..6d32b2b
--- /dev/null
+++ b/src/drv/ps1/event/src/disable.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_disable(const int event)
+{
+ return DisableEvent(event);
+}
diff --git a/src/drv/ps1/event/src/enable.c b/src/drv/ps1/event/src/enable.c
new file mode 100644
index 0000000..3368ac4
--- /dev/null
+++ b/src/drv/ps1/event/src/enable.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_enable(const int event)
+{
+ return EnableEvent(event);
+}
diff --git a/src/drv/ps1/event/src/open.c b/src/drv/ps1/event/src/open.c
new file mode 100644
index 0000000..6bb55f1
--- /dev/null
+++ b/src/drv/ps1/event/src/open.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_open(const int class, const int spec, const int mode,
+ int (*const f)(void))
+{
+ int ret;
+
+ EnterCriticalSection();
+ ret = OpenEvent(class, spec, mode, f);
+ ExitCriticalSection();
+ return ret;
+}
diff --git a/src/drv/ps1/event/src/test.c b/src/drv/ps1/event/src/test.c
new file mode 100644
index 0000000..358bd8e
--- /dev/null
+++ b/src/drv/ps1/event/src/test.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/event.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_event_test(const int event)
+{
+ int ret;
+
+ ret = TestEvent(event);
+ return ret;
+}
diff --git a/src/drv/ps1/gpu/CMakeLists.txt b/src/drv/ps1/gpu/CMakeLists.txt
new file mode 100644
index 0000000..a86ab92
--- /dev/null
+++ b/src/drv/ps1/gpu/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_gpu INTERFACE)
+target_include_directories(drv_ps1_gpu INTERFACE include)
diff --git a/src/drv/ps1/gpu/include/drv/ps1/gpu.h b/src/drv/ps1/gpu/include/drv/ps1/gpu.h
new file mode 100644
index 0000000..1afc5f6
--- /dev/null
+++ b/src/drv/ps1/gpu/include/drv/ps1/gpu.h
@@ -0,0 +1,173 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_GPU_H
+#define DRV_PS1_GPU_H
+
+#include <stdint.h>
+
+enum
+{
+ GP0_FILL_VRAM = 0x02,
+ GP0_TEXTRECT_VARSZ_OPAQ_RAW = 0x65,
+ GP0_COPY_RECT_CPU_VRAM = 0xa0,
+ GP0_COPY_RECT_VRAM_CPU = 0xc0,
+ GP0_DRAW_MODE = 0xe1,
+ GP0_TEX_WINDOW,
+ GP0_DRAW_AREA_TOP_LEFT,
+ GP0_DRAW_AREA_BOTTOM_RIGHT,
+ GP0_DRAW_OFFSET,
+ GP0_DRAW_MASK_BIT
+};
+
+enum
+{
+ GP1_RESET_GPU,
+ GP1_RESET_CMDBUF,
+ GP1_ACK_IRQ,
+ GP1_DISPLAY_ENABLE,
+ GP1_DMA_DIR,
+ GP1_START_DISPLAY_AREA,
+ GP1_H_DISPLAY_RANGE,
+ GP1_V_DISPLAY_RANGE,
+ GP1_DISPLAY_MODE
+};
+
+enum
+{
+ GP1_DMA_DIR_OFF,
+ GP1_DMA_DIR_FIFO,
+ GP1_DMA_DIR_CPU_TO_GP0,
+ GP1_DMA_DIR_GPUREAD_TO_CPU
+};
+
+union drv_ps1_gpu_gp0
+{
+ uint32_t mask;
+
+ struct
+ {
+ uint32_t w :16, h :16, x :16, y :16, r :8, g :8, b :8, cmd :8;
+ } fill_vram;
+
+ struct
+ {
+ uint32_t :24, cmd :8;
+ } copy_rect;
+
+ struct
+ {
+ uint16_t x, y;
+ } coord;
+
+ struct
+ {
+ uint16_t w, h;
+ } size;
+
+ struct
+ {
+ uint32_t page_x :4, page_y :1, stp :2, bpp :2, dither :1,
+ draw_to_display :1, tex_disable :1, xflip :1, yflip :1, :10,
+ cmd :8;
+ } draw_mode;
+
+ struct
+ {
+ uint32_t mask_x :5, mask_y :5, off_x :5, off_y :5, :4, cmd :8;
+ } tex_window;
+
+ struct
+ {
+ uint32_t x :10, y :9, :5, cmd :8;
+ } draw_area_tl, draw_area_br;
+
+ struct
+ {
+ int32_t x :11, y :11, :2, cmd :8;
+ } offset;
+
+ struct
+ {
+ uint32_t set :1, check :1, :22, cmd :8;
+ } mask_bit;
+};
+
+union drv_ps1_gpu_gp1
+{
+ uint32_t mask;
+
+ struct
+ {
+ uint32_t :24, cmd:8;
+ } reset_gpu, reset_cmdbuf, ack_irq;
+
+ struct
+ {
+ uint32_t disable :1, :23, cmd :8;
+ } display;
+
+ struct
+ {
+ uint32_t dir :2, :22, cmd :8;
+ } dma;
+
+ struct
+ {
+ uint32_t x :10, y :9, :5, cmd :8;
+ } disparea;
+
+ struct
+ {
+ uint32_t x1 :12, x2 :12, cmd :8;
+ } h_display_range;
+
+ struct
+ {
+ uint32_t y1 :10, y2 :10, :4, cmd :8;
+ } v_display_range;
+
+ struct
+ {
+ uint32_t hres :2, vres :1, vmode :1, coldepth :1, vinterlace :1,
+ hres2 :1, reverse :1, :16, cmd :8;
+ } display_mode;
+};
+
+union drv_ps1_gpu_stat
+{
+ struct
+ {
+ uint32_t x_base :4, y_base :1, stp :2, bpp :2, dither :1,
+ draw_to_display :1, set_mask :1, draw_pix :1, interlace :1,
+ reverse :1, disable :1, xres2 :1, xres1 :2, yres :1, vmode :1,
+ coldepth :1, vinterlace :1, display_enable :1, irq_req :1,
+ dma_req :1, ready_cmd :1, ready_send :1, ready_dma :1, dma_dir :2,
+ draw_odd :1;
+ } bits;
+
+ uint32_t mask;
+};
+
+#define GPU_BASE 0x1f801810
+#define GPU_REG(x) (GPU_BASE + (x))
+#define GP0 ((volatile union drv_ps1_gpu_gp0 *)GPU_REG(0))
+#define GP1 ((volatile union drv_ps1_gpu_gp1 *)GPU_REG(4))
+#define GPUSTAT ((volatile const union drv_ps1_gpu_stat *)GPU_REG(4))
+
+#endif
diff --git a/src/drv/ps1/include/drv/ps1.h b/src/drv/ps1/include/drv/ps1.h
new file mode 100644
index 0000000..7d92878
--- /dev/null
+++ b/src/drv/ps1/include/drv/ps1.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_H
+#define DRV_PS1_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_ps1_init(const struct drv_event *ev);
+int drv_ps1_update(struct drv_port *p);
+void drv_ps1_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/ps1/irq/CMakeLists.txt b/src/drv/ps1/irq/CMakeLists.txt
new file mode 100644
index 0000000..8327cd5
--- /dev/null
+++ b/src/drv/ps1/irq/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_irq)
+add_subdirectory(src)
+target_include_directories(drv_ps1_irq PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_irq PUBLIC c PRIVATE drv_ps1_bios)
diff --git a/src/drv/ps1/irq/include/drv/ps1/irq.h b/src/drv/ps1/irq/include/drv/ps1/irq.h
new file mode 100644
index 0000000..0d40c7f
--- /dev/null
+++ b/src/drv/ps1/irq/include/drv/ps1/irq.h
@@ -0,0 +1,64 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_IRQ_H
+#define DRV_PS1_IRQ_H
+
+#include <stdint.h>
+
+union drv_ps1_statmask
+{
+ struct
+ {
+ uint32_t vblank :1, gpu :1, cdrom :1, dma :1, tmr0 :1, tmr1 :1, tmr2 :1,
+ controller :1, sio :1, spu :1, lightpen :1, :21;
+ } bits;
+
+ uint32_t mask;
+};
+
+#define I_BASE(x) (0x1f801070 + (x))
+#define I_STAT ((volatile union drv_ps1_statmask *)I_BASE(0))
+#define I_MASK ((volatile union drv_ps1_statmask *)I_BASE(4))
+
+enum drv_ps1_irq
+{
+ IRQ_VBLANK,
+ IRQ_GPU,
+ IRQ_CDROM,
+ IRQ_DMA,
+ IRQ_TMR0,
+ IRQ_TMR1,
+ IRQ_TMR2,
+ IRQ_JOYPAD_MEMCARD,
+ IRQ_SIO,
+ IRQ_SPU,
+ IRQ_JOYPAD_IO
+};
+
+struct drv_ps1_irq_src
+{
+ int mask;
+ int (*fn)(void);
+ struct drv_ps1_irq_src *next;
+};
+
+int drv_ps1_irq_init(void);
+int drv_ps1_irq_set(struct drv_ps1_irq_src *src);
+
+#endif
diff --git a/src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h b/src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h
new file mode 100644
index 0000000..39b7448
--- /dev/null
+++ b/src/drv/ps1/irq/private_include/drv/ps1/irq/routines.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_IRQ_ROUTINES_H
+#define DRV_PS1_IRQ_ROUTINES_H
+
+void drv_ps1_irq_handler(void);
+
+#endif
diff --git a/src/drv/ps1/irq/private_include/drv/ps1/irq/types.h b/src/drv/ps1/irq/private_include/drv/ps1/irq/types.h
new file mode 100644
index 0000000..6c5a185
--- /dev/null
+++ b/src/drv/ps1/irq/private_include/drv/ps1/irq/types.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_IRQ_TYPES_H
+#define DRV_PS1_IRQ_TYPES_H
+
+#include <drv/ps1/irq.h>
+
+extern struct drv_ps1_irq_src *drv_ps1_irq_head;
+
+#endif
diff --git a/src/drv/ps1/irq/src/CMakeLists.txt b/src/drv/ps1/irq/src/CMakeLists.txt
new file mode 100644
index 0000000..3823f4e
--- /dev/null
+++ b/src/drv/ps1/irq/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_irq PRIVATE
+ handler.c
+ head.c
+ init.c
+ set.c
+)
diff --git a/src/drv/ps1/irq/src/handler.c b/src/drv/ps1/irq/src/handler.c
new file mode 100644
index 0000000..0861852
--- /dev/null
+++ b/src/drv/ps1/irq/src/handler.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/routines.h>
+#include <drv/ps1/irq/types.h>
+#include <drv/ps1/bios.h>
+#include <stddef.h>
+
+void drv_ps1_irq_handler(void)
+{
+ for (struct drv_ps1_irq_src *s = drv_ps1_irq_head; s; s = s->next)
+ if (I_STAT->mask & s->mask)
+ s->fn();
+
+ ReturnFromException();
+}
diff --git a/src/drv/ps1/irq/src/head.c b/src/drv/ps1/irq/src/head.c
new file mode 100644
index 0000000..cde1fd8
--- /dev/null
+++ b/src/drv/ps1/irq/src/head.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/types.h>
+
+struct drv_ps1_irq_src *drv_ps1_irq_head;
diff --git a/src/drv/ps1/irq/src/init.c b/src/drv/ps1/irq/src/init.c
new file mode 100644
index 0000000..9e92b01
--- /dev/null
+++ b/src/drv/ps1/irq/src/init.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/routines.h>
+#include <drv/ps1/bios.h>
+#include <setjmp.h>
+
+int drv_ps1_irq_init(void)
+{
+ static jmp_buf jmp;
+ static char stack[128];
+ const int critical = EnterCriticalSection();
+
+ if (SaveState(jmp))
+ drv_ps1_irq_handler();
+
+ jmp->sp = (unsigned)stack + sizeof stack - 4;
+ SetCustomExitFromException(jmp);
+
+ if (critical)
+ ExitCriticalSection();
+
+ return 0;
+}
diff --git a/src/drv/ps1/irq/src/set.c b/src/drv/ps1/irq/src/set.c
new file mode 100644
index 0000000..35c5ed0
--- /dev/null
+++ b/src/drv/ps1/irq/src/set.c
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/irq.h>
+#include <drv/ps1/irq/types.h>
+#include <drv/ps1/bios.h>
+
+int drv_ps1_irq_set(struct drv_ps1_irq_src *const src)
+{
+ if (!drv_ps1_irq_head)
+ drv_ps1_irq_head = src;
+ else
+ for (struct drv_ps1_irq_src *s = drv_ps1_irq_head; s; s = s->next)
+ if (!s->next)
+ {
+ s->next = src;
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/drv/ps1/mc/CMakeLists.txt b/src/drv/ps1/mc/CMakeLists.txt
new file mode 100644
index 0000000..ef232ef
--- /dev/null
+++ b/src/drv/ps1/mc/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_mc)
+add_subdirectory(src)
+target_include_directories(drv_ps1_mc PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_mc PUBLIC c drv_event)
diff --git a/src/drv/ps1/mc/include/drv/ps1/mc.h b/src/drv/ps1/mc/include/drv/ps1/mc.h
new file mode 100644
index 0000000..2e90776
--- /dev/null
+++ b/src/drv/ps1/mc/include/drv/ps1/mc.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_MC_H
+#define DRV_PS1_MC_H
+
+#include <drv/event.h>
+
+struct drv_ps1_mc *drv_ps1_mc_init(const struct drv_event *ev);
+int drv_ps1_mc_update(struct drv_ps1_mc *mc);
+void drv_ps1_mc_free(struct drv_ps1_mc *mc);
+
+#endif
diff --git a/src/drv/ps1/mc/private_include/drv/ps1/mc/types.h b/src/drv/ps1/mc/private_include/drv/ps1/mc/types.h
new file mode 100644
index 0000000..14606e5
--- /dev/null
+++ b/src/drv/ps1/mc/private_include/drv/ps1/mc/types.h
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_MC_TYPES_H
+#define DRV_PS1_MC_TYPES_H
+
+#include <drv/event.h>
+
+struct drv_ps1_mc
+{
+ const struct drv_event *ev;
+};
+
+enum
+{
+ MC_0,
+ MC_1,
+
+ N_MC
+};
+
+#endif
diff --git a/src/drv/ps1/mc/src/CMakeLists.txt b/src/drv/ps1/mc/src/CMakeLists.txt
new file mode 100644
index 0000000..ae1378c
--- /dev/null
+++ b/src/drv/ps1/mc/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_mc PRIVATE
+ free.c
+ init.c
+ update.c
+)
diff --git a/src/drv/ps1/mc/src/free.c b/src/drv/ps1/mc/src/free.c
new file mode 100644
index 0000000..bdf54ff
--- /dev/null
+++ b/src/drv/ps1/mc/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/mc.h>
+
+void drv_ps1_mc_free(struct drv_ps1_mc *const mc)
+{
+}
diff --git a/src/drv/ps1/mc/src/init.c b/src/drv/ps1/mc/src/init.c
new file mode 100644
index 0000000..88be46a
--- /dev/null
+++ b/src/drv/ps1/mc/src/init.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/mc.h>
+#include <drv/ps1/mc/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_mc *drv_ps1_mc_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_mc *const ret = malloc(sizeof *ret);
+
+ if (!ret)
+ return NULL;
+
+ *ret = (const struct drv_ps1_mc){.ev = ev};
+ return ret;
+}
diff --git a/src/drv/ps1/mc/src/update.c b/src/drv/ps1/mc/src/update.c
new file mode 100644
index 0000000..866bf94
--- /dev/null
+++ b/src/drv/ps1/mc/src/update.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/mc.h>
+#include <drv/event.h>
+
+int drv_ps1_mc_update(struct drv_ps1_mc *const mc)
+{
+ /* TODO */
+ return 0;
+}
diff --git a/src/drv/ps1/pad/CMakeLists.txt b/src/drv/ps1/pad/CMakeLists.txt
new file mode 100644
index 0000000..eb74091
--- /dev/null
+++ b/src/drv/ps1/pad/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_pad)
+add_subdirectory(src)
+target_include_directories(drv_ps1_pad PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_pad PUBLIC c drv_event)
diff --git a/src/drv/ps1/pad/include/drv/ps1/pad.h b/src/drv/ps1/pad/include/drv/ps1/pad.h
new file mode 100644
index 0000000..9cc2fc6
--- /dev/null
+++ b/src/drv/ps1/pad/include/drv/ps1/pad.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_PAD_H
+#define DRV_PS1_PAD_H
+
+#include <drv/event.h>
+
+struct drv_ps1_pad *drv_ps1_pad_init(const struct drv_event *ev);
+int drv_ps1_pad_update(struct drv_ps1_pad *pad);
+void drv_ps1_pad_free(struct drv_ps1_pad *pad);
+
+#endif
diff --git a/src/drv/ps1/pad/private_include/drv/ps1/pad/types.h b/src/drv/ps1/pad/private_include/drv/ps1/pad/types.h
new file mode 100644
index 0000000..c164a30
--- /dev/null
+++ b/src/drv/ps1/pad/private_include/drv/ps1/pad/types.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_PAD_TYPES_H
+#define DRV_PS1_PAD_TYPES_H
+
+#include <drv/event.h>
+
+struct drv_ps1_pad
+{
+ const struct drv_event *ev;
+};
+
+#endif
diff --git a/src/drv/ps1/pad/src/CMakeLists.txt b/src/drv/ps1/pad/src/CMakeLists.txt
new file mode 100644
index 0000000..bfae1a1
--- /dev/null
+++ b/src/drv/ps1/pad/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_pad PRIVATE
+ free.c
+ init.c
+ update.c
+)
diff --git a/src/drv/ps1/pad/src/free.c b/src/drv/ps1/pad/src/free.c
new file mode 100644
index 0000000..1498f2d
--- /dev/null
+++ b/src/drv/ps1/pad/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/pad.h>
+
+void drv_ps1_pad_free(struct drv_ps1_pad *const pad)
+{
+}
diff --git a/src/drv/ps1/pad/src/init.c b/src/drv/ps1/pad/src/init.c
new file mode 100644
index 0000000..8fe3ccb
--- /dev/null
+++ b/src/drv/ps1/pad/src/init.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/pad.h>
+#include <drv/ps1/pad/types.h>
+#include <drv/event.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv_ps1_pad *drv_ps1_pad_init(const struct drv_event *const ev)
+{
+ struct drv_ps1_pad *const ret = malloc(sizeof *ret);
+
+ if (!ret)
+ return NULL;
+
+ *ret = (const struct drv_ps1_pad){.ev = ev};
+ return ret;
+}
diff --git a/src/drv/ps1/pad/src/update.c b/src/drv/ps1/pad/src/update.c
new file mode 100644
index 0000000..9c9acfe
--- /dev/null
+++ b/src/drv/ps1/pad/src/update.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/pad.h>
+#include <drv/event.h>
+
+int drv_ps1_pad_update(struct drv_ps1_pad *const pad)
+{
+ /* TODO */
+ return 0;
+}
diff --git a/src/drv/ps1/private_include/drv/ps1/types.h b/src/drv/ps1/private_include/drv/ps1/types.h
new file mode 100644
index 0000000..35cb14e
--- /dev/null
+++ b/src/drv/ps1/private_include/drv/ps1/types.h
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_TYPES_H
+#define DRV_PS1_TYPES_H
+
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+
+struct drv_port
+{
+ struct drv_ps1_mc *mc;
+ struct drv_ps1_cd *cd;
+ struct drv_ps1_pad *pad;
+ struct drv_ps1_sio *sio;
+};
+
+#endif
diff --git a/src/drv/ps1/rcnt/CMakeLists.txt b/src/drv/ps1/rcnt/CMakeLists.txt
new file mode 100644
index 0000000..f5b5171
--- /dev/null
+++ b/src/drv/ps1/rcnt/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_rcnt)
+add_subdirectory(src)
+target_include_directories(drv_ps1_rcnt PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_rcnt
+ PUBLIC c
+ PRIVATE drv_ps1_bios drv_ps1_irq drv_ps1_event)
diff --git a/src/drv/ps1/rcnt/include/drv/ps1/rcnt.h b/src/drv/ps1/rcnt/include/drv/ps1/rcnt.h
new file mode 100644
index 0000000..831012c
--- /dev/null
+++ b/src/drv/ps1/rcnt/include/drv/ps1/rcnt.h
@@ -0,0 +1,45 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_RCNT_H
+#define DRV_PS1_RCNT_H
+
+#include <stdint.h>
+
+union drv_ps1_rcnt_cfg
+{
+ struct
+ {
+ uint32_t sync_enable :1, sync_mode :2, reset :1, irq_tgt :1,
+ irq_max :1, repeat :1, pulse_toggle :1, clocksrc :2, intreq :1;
+ } bits;
+
+ uint32_t word;
+};
+
+enum drv_ps1_rcnt
+{
+ DRV_PS1_RCNT0,
+ DRV_PS1_RCNT1,
+ DRV_PS1_RCNT2
+};
+
+int drv_ps1_rcnt_init(enum drv_ps1_rcnt rcnt, uint16_t target,
+ const union drv_ps1_rcnt_cfg *cfg, int (*f)(void));
+
+#endif
diff --git a/src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h b/src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h
new file mode 100644
index 0000000..a6c9750
--- /dev/null
+++ b/src/drv/ps1/rcnt/private_include/drv/ps1/rcnt/regs.h
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_RCNT_REGS_H
+#define DRV_PS1_RCNT_REGS_H
+
+#include <drv/ps1/rcnt.h>
+#include <stdint.h>
+
+struct rcnt_value
+{
+ uint32_t value :16, :16;
+};
+
+#define RCNT_BASE(n) (0x1f801100 + (n << 4))
+#define RCNT_REG(n, m) (RCNT_BASE(n) + m)
+#define RCNT_VALUE(n) ((volatile struct rcnt_value *)RCNT_REG(n, 0))
+#define RCNT_MODE(n) ((volatile union drv_ps1_rcnt_cfg *)RCNT_REG(n, 4))
+#define RCNT_TARGET(n) ((volatile struct rcnt_value *)RCNT_REG(n, 8))
+
+#endif
diff --git a/src/drv/ps1/rcnt/src/CMakeLists.txt b/src/drv/ps1/rcnt/src/CMakeLists.txt
new file mode 100644
index 0000000..4e8eb88
--- /dev/null
+++ b/src/drv/ps1/rcnt/src/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_rcnt PRIVATE
+ init.c
+)
diff --git a/src/drv/ps1/rcnt/src/init.c b/src/drv/ps1/rcnt/src/init.c
new file mode 100644
index 0000000..0c4327c
--- /dev/null
+++ b/src/drv/ps1/rcnt/src/init.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/rcnt.h>
+#include <drv/ps1/rcnt/regs.h>
+#include <drv/ps1/event.h>
+#include <drv/ps1/irq.h>
+#include <drv/ps1/bios.h>
+#include <stddef.h>
+#include <stdint.h>
+
+int drv_ps1_rcnt_init(const enum drv_ps1_rcnt rcnt, const uint16_t target,
+ const union drv_ps1_rcnt_cfg *const cfg, int (*const f)(void))
+{
+ int class;
+
+ EnterCriticalSection();
+ RCNT_TARGET(rcnt)->value = target;
+ *RCNT_MODE(rcnt) = *cfg;
+
+ switch (rcnt)
+ {
+ case DRV_PS1_RCNT0:
+ I_MASK->bits.tmr0 = 1;
+ class = CLASS_RTC0;
+ break;
+ case DRV_PS1_RCNT1:
+ I_MASK->bits.tmr1 = 1;
+ class = CLASS_RTC1;
+ break;
+ case DRV_PS1_RCNT2:
+ I_MASK->bits.tmr2 = 1;
+ class = CLASS_RTC2;
+ break;
+ }
+
+ ExitCriticalSection();
+
+ const int event = drv_ps1_event_open(class, SPEC_INTERRUPTED,
+ MODE_EXECUTE, f);
+
+ if (event == -1)
+ return -1;
+
+ drv_ps1_event_enable(event);
+ return 0;
+}
diff --git a/src/drv/ps1/sio/CMakeLists.txt b/src/drv/ps1/sio/CMakeLists.txt
new file mode 100644
index 0000000..f382e08
--- /dev/null
+++ b/src/drv/ps1/sio/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_sio)
+add_subdirectory(src)
+target_include_directories(drv_ps1_sio PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_sio
+ PUBLIC c
+ PRIVATE drv drv_ps1_bios drv_ps1_cpu drv_ps1_irq)
diff --git a/src/drv/ps1/sio/include/drv/ps1/sio.h b/src/drv/ps1/sio/include/drv/ps1/sio.h
new file mode 100644
index 0000000..3fabadd
--- /dev/null
+++ b/src/drv/ps1/sio/include/drv/ps1/sio.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_H
+#define DRV_PS1_SIO_H
+
+#include <drv/event.h>
+
+struct drv_ps1_sio *drv_ps1_sio_init(const struct drv_event *ev);
+int drv_ps1_sio_update(struct drv_ps1_sio *sio);
+void drv_ps1_sio_free(struct drv_ps1_sio *sio);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
new file mode 100644
index 0000000..a481fa9
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/ops.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_OPS_H
+#define DRV_PS1_SIO_OPS_H
+
+#include <drv/event.h>
+#include <sys/types.h>
+
+int drv_ps1_sio_read(void *buf, size_t n, off_t offset,
+ const struct drv_event_done *done, void *args);
+int drv_ps1_sio_read_nb(void *buf, size_t n, void *args);
+int drv_ps1_sio_write(const void *buf, size_t n,
+ const struct drv_event_done *done, void *args);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h
new file mode 100644
index 0000000..16b2bca
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/regs.h
@@ -0,0 +1,136 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_REGS_H
+#define DRV_PS1_SIO_REGS_H
+
+#include <stdint.h>
+
+struct sio_tx_data
+{
+ uint32_t value :8, :24;
+};
+
+struct sio_rx_data
+{
+ uint8_t values[4];
+};
+
+union sio_stat
+{
+ struct
+ {
+ uint32_t
+ tx_ready_started :1,
+ rx_fifo_not_empty :1,
+ tx_ready_finished :1,
+ rx_parity_error :1,
+ rx_fifo_overrun :1,
+ rx_bad_stp :1,
+ rx_inverted :1,
+ dsr :1,
+ cts :1,
+ irqreq :1,
+ :1,
+ baudrate :15, :6;
+ } bits;
+
+ uint32_t mask;
+};
+
+union sio_mode
+{
+ struct
+ {
+ uint16_t
+ baudrate_mul :2,
+ len :2,
+ parity_en :1,
+ parity_odd :1,
+ stplen :2,
+ :8;
+ } bits;
+
+ uint16_t mask;
+};
+
+union sio_ctrl
+{
+ struct
+ {
+ uint16_t
+ tx_en :1,
+ dtr :1,
+ rx_en :1,
+ tx_invert :1,
+ ack :1,
+ rts :1,
+ reset :1,
+ :1,
+ rx_int_mode :2,
+ tx_int_en :1,
+ rx_int_en :1,
+ dsr_int_en :1,
+ :3;
+ } bits;
+
+ uint16_t mask;
+};
+
+enum
+{
+ SIO_CTRL_RX_INT_1,
+ SIO_CTRL_RX_INT_2,
+ SIO_CTRL_RX_INT_3,
+ SIO_CTRL_RX_INT_4
+};
+
+enum
+{
+ SIO_MODE_FACTOR_STOP,
+ SIO_MODE_FACTOR_MUL1,
+ SIO_MODE_FACTOR_MUL16,
+ SIO_MODE_FACTOR_MUL64
+};
+
+enum
+{
+ SIO_MODE_LEN_5,
+ SIO_MODE_LEN_6,
+ SIO_MODE_LEN_7,
+ SIO_MODE_LEN_8
+};
+
+enum
+{
+ SIO_MODE_STP_RESERVED,
+ SIO_MODE_STP_1,
+ SIO_MODE_STP_1_5,
+ SIO_MODE_STP_2,
+};
+
+#define SIO_BASE 0x1f801050
+#define SIO_REG(n) (SIO_BASE + n)
+#define SIO_TX_DATA ((volatile struct sio_tx_data *)SIO_REG(0))
+#define SIO_RX_DATA ((const volatile struct sio_rx_data *)SIO_REG(0))
+#define SIO_STAT ((const volatile union sio_stat *)SIO_REG(4))
+#define SIO_MODE ((volatile union sio_mode *)SIO_REG(8))
+#define SIO_CTRL ((volatile union sio_ctrl *)SIO_REG(10))
+#define SIO_BAUD (*(volatile uint16_t *)SIO_REG(14))
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h
new file mode 100644
index 0000000..f5b97da
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/routines.h
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_ROUTINES_H
+#define DRV_PS1_SIO_ROUTINES_H
+
+#include <drv/ps1/sio/types.h>
+
+int drv_ps1_sio_irq(void);
+int drv_ps1_sio_next(struct sio_fifo *f);
+
+#endif
diff --git a/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h b/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h
new file mode 100644
index 0000000..87dd412
--- /dev/null
+++ b/src/drv/ps1/sio/private_include/drv/ps1/sio/types.h
@@ -0,0 +1,65 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_SIO_TYPES_H
+#define DRV_PS1_SIO_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+
+struct sio_req
+{
+ union
+ {
+ struct sio_req_r
+ {
+ void *buf;
+ size_t n;
+ } r;
+
+ struct sio_req_w
+ {
+ const void *buf;
+ size_t n;
+ } w;
+ } u;
+
+ int (*f)(void);
+ struct drv_event_done done;
+ struct sio_req *next;
+};
+
+struct sio_fifo
+{
+ char buf[192];
+ size_t proc, pend;
+ struct sio_req *head, *tail;
+ int (*next)(void);
+};
+
+struct drv_ps1_sio
+{
+ bool init;
+ int event;
+ struct sio_fifo rx, tx;
+ struct drv_event ev;
+};
+
+extern struct drv_ps1_sio drv_ps1_sio;
+
+#endif
diff --git a/src/drv/ps1/sio/src/CMakeLists.txt b/src/drv/ps1/sio/src/CMakeLists.txt
new file mode 100644
index 0000000..1bcf5cf
--- /dev/null
+++ b/src/drv/ps1/sio/src/CMakeLists.txt
@@ -0,0 +1,29 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_sio PRIVATE
+ free.c
+ globals.c
+ init.c
+ irq.c
+ next.c
+ read.c
+ read_nb.c
+ update.c
+ write.c
+)
+
+target_link_libraries(drv_ps1_sio PRIVATE kprintf)
diff --git a/src/drv/ps1/sio/src/free.c b/src/drv/ps1/sio/src/free.c
new file mode 100644
index 0000000..5c506d0
--- /dev/null
+++ b/src/drv/ps1/sio/src/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+
+void drv_ps1_sio_free(struct drv_ps1_sio *const sio)
+{
+}
diff --git a/src/drv/ps1/sio/src/globals.c b/src/drv/ps1/sio/src/globals.c
new file mode 100644
index 0000000..35c72b8
--- /dev/null
+++ b/src/drv/ps1/sio/src/globals.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/types.h>
+
+struct drv_ps1_sio drv_ps1_sio;
diff --git a/src/drv/ps1/sio/src/init.c b/src/drv/ps1/sio/src/init.c
new file mode 100644
index 0000000..6bf44fc
--- /dev/null
+++ b/src/drv/ps1/sio/src/init.c
@@ -0,0 +1,70 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cpu.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+
+struct drv_ps1_sio *drv_ps1_sio_init(const struct drv_event *const ev)
+{
+ const unsigned long baudrate = 115200ul;
+
+ SIO_CTRL->bits.reset = 1;
+ SIO_BAUD = DRV_PS1_CPU_F / (16 * baudrate);
+ SIO_MODE->mask = (const union sio_mode)
+ {
+ .bits =
+ {
+ .baudrate_mul = SIO_MODE_FACTOR_MUL16,
+ .stplen = SIO_MODE_STP_1,
+ .len = SIO_MODE_LEN_8
+ }
+ }.mask;
+
+ SIO_CTRL->mask = (const union sio_ctrl)
+ {
+ .bits =
+ {
+ .rx_int_mode = SIO_CTRL_RX_INT_1,
+ .rx_int_en = 1,
+ .tx_en = 1,
+ .rx_en = 1,
+ .rts = 1,
+ .dtr = 1
+ }
+ }.mask;
+
+ static struct drv_ps1_irq_src src =
+ {
+ .mask = 1 << IRQ_SIO,
+ .fn = drv_ps1_sio_irq
+ };
+
+ if (drv_ps1_irq_set(&src))
+ return NULL;
+
+ I_MASK->bits.sio = 1;
+ drv_ps1_sio.ev = *ev;
+ return &drv_ps1_sio;
+}
diff --git a/src/drv/ps1/sio/src/irq.c b/src/drv/ps1/sio/src/irq.c
new file mode 100644
index 0000000..5a19d83
--- /dev/null
+++ b/src/drv/ps1/sio/src/irq.c
@@ -0,0 +1,71 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cpu.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+
+int irq_sio_overrun;
+
+static int read_rx(struct sio_fifo *const f)
+{
+ const unsigned char v = *SIO_RX_DATA->values;
+ size_t n = f->pend + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ if (n == f->proc)
+ {
+ irq_sio_overrun = 1;
+ return -1;
+ }
+
+ f->buf[f->pend = n] = v;
+ return 0;
+}
+
+volatile unsigned sio_read;
+volatile int sw_overrun;
+
+int drv_ps1_sio_irq(void)
+{
+ SIO_CTRL->bits.rts = 0;
+
+ while (SIO_STAT->bits.rx_fifo_not_empty)
+ {
+ if (read_rx(&drv_ps1_sio.rx))
+ {
+ sw_overrun = 1;
+ break;
+ }
+
+ sio_read++;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_STAT->bits.sio = 0;
+ SIO_CTRL->bits.ack = 1;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/next.c b/src/drv/ps1/sio/src/next.c
new file mode 100644
index 0000000..4c330ab
--- /dev/null
+++ b/src/drv/ps1/sio/src/next.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int drv_ps1_sio_next(struct sio_fifo *const f)
+{
+ struct sio_req *const next = f->head->next;
+
+ free(f->head);
+
+ f->next = next ? next->f : NULL;
+ f->head = next;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/read.c b/src/drv/ps1/sio/src/read.c
new file mode 100644
index 0000000..e13ad29
--- /dev/null
+++ b/src/drv/ps1/sio/src/read.c
@@ -0,0 +1,125 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/irq.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+
+static int load(void);
+
+static int check(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = f->head;
+ struct sio_req_r *const r = &req->u.r;
+
+ if (!r->n)
+ {
+ const struct drv_event_done *const d = &req->done;
+
+ if (d->f && d->f(SUCCESS, d->args))
+ return -1;
+
+ return drv_ps1_sio_next(f);
+ }
+
+ f->next = load;
+ return 0;
+}
+
+static void read_fifo(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = f->head;
+ struct sio_req_r *const r = &req->u.r;
+ char *p = r->buf;
+
+ I_MASK->bits.sio = 0;
+ SIO_CTRL->bits.rts = 0;
+
+ while (r->n)
+ {
+ if (f->pend == f->proc)
+ break;
+
+ size_t n = f->proc + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ *p++ = f->buf[f->proc = n];
+ r->buf = p;
+ r->n--;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_MASK->bits.sio = 1;
+}
+
+static int load(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req_r *const r = &f->head->u.r;
+
+ read_fifo(s);
+
+ if (!r->n)
+ f->next = check;
+
+ return 0;
+}
+
+int drv_ps1_sio_read(void *const buf, const size_t n, const off_t offset,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+ struct sio_req *const req = malloc(sizeof *req);
+
+ if (!req)
+ return -1;
+
+ *req = (const struct sio_req)
+ {
+ .f = load,
+ .done = *done,
+ .u.r =
+ {
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!f->head)
+ f->head = req;
+ else
+ f->tail->next = req;
+
+ f->tail = req;
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/read_nb.c b/src/drv/ps1/sio/src/read_nb.c
new file mode 100644
index 0000000..755c5cf
--- /dev/null
+++ b/src/drv/ps1/sio/src/read_nb.c
@@ -0,0 +1,61 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/irq.h>
+#include <drv/ps1/bios.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+
+static int read_fifo(char *buf, size_t n)
+{
+ int ret = 0;
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->rx;
+
+ I_MASK->bits.sio = 0;
+ SIO_CTRL->bits.rts = 0;
+
+ while (n)
+ {
+ if (f->pend == f->proc)
+ break;
+
+ size_t m = f->proc + 1;
+
+ if (m >= sizeof f->buf)
+ m = 0;
+
+ *buf++ = f->buf[f->proc = m];
+ n--;
+ ret++;
+ }
+
+ SIO_CTRL->bits.rts = 1;
+ I_MASK->bits.sio = 1;
+ return ret;
+}
+
+int drv_ps1_sio_read_nb(void *const buf, const size_t n, void *const args)
+{
+ return read_fifo(buf, n);
+}
diff --git a/src/drv/ps1/sio/src/update.c b/src/drv/ps1/sio/src/update.c
new file mode 100644
index 0000000..eac875c
--- /dev/null
+++ b/src/drv/ps1/sio/src/update.c
@@ -0,0 +1,98 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio.h>
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/regs.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+static int init(struct drv_ps1_sio *const s)
+{
+ if (s->init)
+ return 0;
+
+ const struct drv_event *const ev = &s->ev;
+ static const struct drv_event_ops ops =
+ {
+ .read = drv_ps1_sio_read,
+ .read_nb = drv_ps1_sio_read_nb,
+ .write = drv_ps1_sio_write
+ };
+
+ if (ev->status("ttyS0", &ops, true, 0660, ev->args))
+ return -1;
+
+ s->init = true;
+ return 0;
+}
+
+static int rx(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->rx;
+
+ if (f->next)
+ return f->next();
+ else if (f->head)
+ f->next = f->head->f;
+
+ return 0;
+}
+
+static void write_tx(struct sio_fifo *const f)
+{
+ if (f->proc == f->pend)
+ return;
+
+ size_t n = f->proc + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+
+ SIO_TX_DATA->value = f->buf[f->proc = n];
+}
+
+static int tx(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->tx;
+
+ if (SIO_STAT->bits.tx_ready_started)
+ write_tx(f);
+
+ if (f->next)
+ return f->next();
+ else if (f->head)
+ f->next = f->head->f;
+
+ return 0;
+}
+
+int drv_ps1_sio_update(struct drv_ps1_sio *const s)
+{
+ if (SIO_STAT->bits.rx_fifo_overrun)
+ SIO_CTRL->bits.ack = 1;
+
+ if (init(s) || rx(s) || tx(s))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/ps1/sio/src/write.c b/src/drv/ps1/sio/src/write.c
new file mode 100644
index 0000000..942456f
--- /dev/null
+++ b/src/drv/ps1/sio/src/write.c
@@ -0,0 +1,117 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/sio/ops.h>
+#include <drv/ps1/sio/routines.h>
+#include <drv/ps1/sio/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/event.h>
+#include <kprintf.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+static int store(void);
+
+static void write_fifo(struct drv_ps1_sio *const s)
+{
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const r = f->head;
+ struct sio_req_w *const w = &r->u.w;
+ const char *p = w->buf;
+
+ while (w->n)
+ {
+ size_t n = f->pend + 1;
+
+ if (n >= sizeof f->buf)
+ n = 0;
+ else if (n == f->proc)
+ break;
+
+ f->buf[f->pend = n] = *p++;
+ w->buf = p;
+ w->n--;
+ }
+}
+
+static int check(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const r = f->head;
+ struct sio_req_w *const w = &r->u.w;
+
+ if (!w->n)
+ {
+ const struct drv_event_done *const d = &r->done;
+
+ if (d->f && d->f(SUCCESS, d->args))
+ return -1;
+
+ return drv_ps1_sio_next(f);
+ }
+
+ f->next = store;
+ return 0;
+}
+
+static int store(void)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req_w *const w = &f->head->u.w;
+
+ write_fifo(s);
+
+ if (!w->n)
+ f->next = check;
+
+ return 0;
+}
+
+int drv_ps1_sio_write(const void *const buf, const size_t n,
+ const struct drv_event_done *const done, void *const args)
+{
+ struct drv_ps1_sio *const s = &drv_ps1_sio;
+ struct sio_fifo *const f = &s->tx;
+ struct sio_req *const req = malloc(sizeof *req);
+
+ if (!req)
+ return -1;
+
+ *req = (const struct sio_req)
+ {
+ .f = store,
+ .done = *done,
+ .u.w =
+ {
+ .buf = buf,
+ .n = n
+ }
+ };
+
+ if (!f->head)
+ f->head = req;
+ else
+ f->tail->next = req;
+
+ f->tail = req;
+ return 0;
+}
diff --git a/src/drv/ps1/src/CMakeLists.txt b/src/drv/ps1/src/CMakeLists.txt
new file mode 100644
index 0000000..34042e3
--- /dev/null
+++ b/src/drv/ps1/src/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1 PRIVATE
+ free.c
+ init.c
+ update.c
+)
diff --git a/src/drv/ps1/src/free.c b/src/drv/ps1/src/free.c
new file mode 100644
index 0000000..62be1b1
--- /dev/null
+++ b/src/drv/ps1/src/free.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1.h>
+#include <drv/ps1/types.h>
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+
+void drv_ps1_free(struct drv_port *const p)
+{
+ drv_ps1_mc_free(p->mc);
+ drv_ps1_cd_free(p->cd);
+ drv_ps1_pad_free(p->pad);
+ drv_ps1_sio_free(p->sio);
+}
diff --git a/src/drv/ps1/src/init.c b/src/drv/ps1/src/init.c
new file mode 100644
index 0000000..8ee92a6
--- /dev/null
+++ b/src/drv/ps1/src/init.c
@@ -0,0 +1,59 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1.h>
+#include <drv/ps1/types.h>
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+#include <stdlib.h>
+
+struct drv_port *drv_ps1_init(const struct drv_event *const ev)
+{
+ struct drv_port *ret = NULL;
+ struct drv_ps1_mc *mc = NULL;
+ struct drv_ps1_cd *cd = NULL;
+ struct drv_ps1_pad *pad = NULL;
+ struct drv_ps1_sio *sio = NULL;
+
+ if (!(mc = drv_ps1_mc_init(ev))
+ || !(cd = drv_ps1_cd_init(ev))
+ || !(pad = drv_ps1_pad_init(ev))
+ || !(sio = drv_ps1_sio_init(ev))
+ || !(ret = malloc(sizeof *ret)))
+ goto failure;
+
+ *ret = (const struct drv_port)
+ {
+ .mc = mc,
+ .cd = cd,
+ .pad = pad,
+ .sio = sio
+ };
+
+ return ret;
+
+failure:
+ drv_ps1_mc_free(mc);
+ drv_ps1_cd_free(cd);
+ drv_ps1_pad_free(pad);
+ drv_ps1_sio_free(sio);
+ free(mc);
+ return NULL;
+}
diff --git a/src/drv/ps1/src/update.c b/src/drv/ps1/src/update.c
new file mode 100644
index 0000000..49b22bb
--- /dev/null
+++ b/src/drv/ps1/src/update.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1.h>
+#include <drv/ps1/types.h>
+#include <drv/ps1/cd.h>
+#include <drv/ps1/mc.h>
+#include <drv/ps1/pad.h>
+#include <drv/ps1/sio.h>
+
+int drv_ps1_update(struct drv_port *const p)
+{
+ if (drv_ps1_mc_update(p->mc)
+ || drv_ps1_cd_update(p->cd)
+ || drv_ps1_pad_update(p->pad)
+ || drv_ps1_sio_update(p->sio))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/ps1/time/CMakeLists.txt b/src/drv/ps1/time/CMakeLists.txt
new file mode 100644
index 0000000..93c0143
--- /dev/null
+++ b/src/drv/ps1/time/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_ps1_time)
+add_subdirectory(src)
+target_include_directories(drv_ps1_time PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_ps1_time
+ PUBLIC c
+ PRIVATE drv drv_ps1_bios drv_ps1_irq drv_ps1_rcnt)
diff --git a/src/drv/ps1/time/include/drv/ps1/time.h b/src/drv/ps1/time/include/drv/ps1/time.h
new file mode 100644
index 0000000..f644b59
--- /dev/null
+++ b/src/drv/ps1/time/include/drv/ps1/time.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_TIME_H
+#define DRV_PS1_TIME_H
+
+int drv_ps1_time_tick(void);
+
+#endif
diff --git a/src/drv/ps1/time/private_include/drv/ps1/time/types.h b/src/drv/ps1/time/private_include/drv/ps1/time/types.h
new file mode 100644
index 0000000..2e673fb
--- /dev/null
+++ b/src/drv/ps1/time/private_include/drv/ps1/time/types.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_PS1_TIME_TYPES_H
+#define DRV_PS1_TIME_TYPES_H
+
+#include <time.h>
+
+extern volatile struct timespec drv_ps1_time;
+
+#endif
diff --git a/src/drv/ps1/time/src/CMakeLists.txt b/src/drv/ps1/time/src/CMakeLists.txt
new file mode 100644
index 0000000..d8ebf38
--- /dev/null
+++ b/src/drv/ps1/time/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_ps1_time PRIVATE
+ gettime.c
+ getres.c
+ globals.c
+ settime.c
+ tick.c
+)
diff --git a/src/drv/ps1/time/src/getres.c b/src/drv/ps1/time/src/getres.c
new file mode 100644
index 0000000..de69ff5
--- /dev/null
+++ b/src/drv/ps1/time/src/getres.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/time.h>
+#include <errno.h>
+#include <time.h>
+
+int drv_time_getres(const clockid_t id, struct timespec *const ts)
+{
+ if (id != CLOCK_REALTIME)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ else if (ts)
+ *ts = (const struct timespec){.tv_nsec = 1000000};
+
+ return 0;
+}
diff --git a/src/drv/ps1/time/src/gettime.c b/src/drv/ps1/time/src/gettime.c
new file mode 100644
index 0000000..0fdbfea
--- /dev/null
+++ b/src/drv/ps1/time/src/gettime.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/time.h>
+#include <drv/ps1/time/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/irq.h>
+#include <errno.h>
+#include <time.h>
+
+int drv_time_gettime(const clockid_t id, struct timespec *const ts)
+{
+ if (id != CLOCK_REALTIME)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ I_MASK->bits.tmr2 = 0;
+ *ts = drv_ps1_time;
+ I_MASK->bits.tmr2 = 1;
+ return 0;
+}
diff --git a/src/drv/ps1/time/src/globals.c b/src/drv/ps1/time/src/globals.c
new file mode 100644
index 0000000..2f53665
--- /dev/null
+++ b/src/drv/ps1/time/src/globals.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/time/types.h>
+#include <time.h>
+
+volatile struct timespec drv_ps1_time;
diff --git a/src/drv/ps1/time/src/settime.c b/src/drv/ps1/time/src/settime.c
new file mode 100644
index 0000000..f2ac5fe
--- /dev/null
+++ b/src/drv/ps1/time/src/settime.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/time.h>
+#include <drv/ps1/time/types.h>
+#include <drv/ps1/bios.h>
+#include <errno.h>
+#include <time.h>
+
+int drv_time_settime(const clockid_t id, const struct timespec *const ts)
+{
+ if (id != CLOCK_REALTIME)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ EnterCriticalSection();
+ drv_ps1_time = *ts;
+ ExitCriticalSection();
+ return 0;
+}
diff --git a/src/drv/ps1/time/src/tick.c b/src/drv/ps1/time/src/tick.c
new file mode 100644
index 0000000..494d8ed
--- /dev/null
+++ b/src/drv/ps1/time/src/tick.c
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/ps1/time.h>
+#include <drv/ps1/time/types.h>
+#include <drv/ps1/irq.h>
+#include <time.h>
+
+int drv_ps1_time_tick(void)
+{
+ int ret = 0;
+ struct timespec ts;
+ volatile struct timespec *const t = &drv_ps1_time;
+
+ if (clock_getres(CLOCK_REALTIME, &ts))
+ ret = -1;
+ else if (t->tv_nsec >= 1000000000 - ts.tv_nsec)
+ {
+ t->tv_sec++;
+ t->tv_nsec = 0;
+ }
+ else
+ t->tv_nsec += ts.tv_nsec;
+
+ I_STAT->bits.tmr2 = 0;
+ return ret;
+}
diff --git a/src/drv/src/CMakeLists.txt b/src/drv/src/CMakeLists.txt
new file mode 100644
index 0000000..e567c1c
--- /dev/null
+++ b/src/drv/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv PRIVATE
+ free.c
+ init.c
+ tree.c
+ update.c
+)
diff --git a/src/drv/src/free.c b/src/drv/src/free.c
new file mode 100644
index 0000000..2c324c0
--- /dev/null
+++ b/src/drv/src/free.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/tree.h>
+#include <drv/types.h>
+#include <stdlib.h>
+
+void drv_free(struct drv *const d)
+{
+ if (d)
+ for (size_t i = 0; i < d->n; i++)
+ drv_tree_free[i](d->ports[i]);
+
+ free(d);
+}
diff --git a/src/drv/src/init.c b/src/drv/src/init.c
new file mode 100644
index 0000000..4b89f15
--- /dev/null
+++ b/src/drv/src/init.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/types.h>
+#include <drv/tree.h>
+#include <drv/port.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct drv *drv_init(const struct drv_event *const ev)
+{
+ size_t init = 0;
+ struct drv *const ret = malloc(sizeof *ret);
+ struct drv_port **const ports = malloc(drv_tree_n * sizeof *ports);
+
+ if (!ports || !ret)
+ goto failure;
+
+ for (size_t i = 0; i < drv_tree_n; i++, init++)
+ {
+ struct drv_port *const p = drv_tree_init[i](ev);
+
+ if (!p)
+ goto failure;
+
+ ports[i] = p;
+ }
+
+ *ret = (const struct drv)
+ {
+ .ports = ports,
+ .n = drv_tree_n
+ };
+
+ return ret;
+
+failure:
+
+ if (ports)
+ for (size_t i = 0; i < init; i++)
+ drv_tree_free[i](ports[i]);
+
+ free(ports);
+ free(ret);
+ return NULL;
+}
diff --git a/src/drv/src/tree.c b/src/drv/src/tree.c
new file mode 100644
index 0000000..d52df3d
--- /dev/null
+++ b/src/drv/src/tree.c
@@ -0,0 +1,51 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/tree.h>
+#include <drv/tty.h>
+#include <drv/port.h>
+#include <stddef.h>
+
+struct drv_port *(*const drv_tree_init[])(const struct drv_event *) =
+{
+#if DRV_PS1
+ drv_ps1_init,
+#endif
+ drv_tty_init
+};
+
+enum {N = sizeof drv_tree_init / sizeof *drv_tree_init};
+
+int (*const drv_tree_update[N])(struct drv_port *) =
+{
+#if DRV_PS1
+ drv_ps1_update,
+#endif
+ drv_tty_update
+};
+
+void (*const drv_tree_free[N])(struct drv_port *) =
+{
+#if DRV_PS1
+ drv_ps1_free,
+#endif
+ drv_tty_free
+};
+
+const size_t drv_tree_n = N;
diff --git a/src/drv/src/update.c b/src/drv/src/update.c
new file mode 100644
index 0000000..268c2b6
--- /dev/null
+++ b/src/drv/src/update.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/drv.h>
+#include <drv/tree.h>
+#include <drv/types.h>
+#include <drv/port.h>
+#include <stddef.h>
+
+int drv_update(struct drv *const d)
+{
+ for (size_t i = 0; i < drv_tree_n; i++)
+ if (drv_tree_update[i](d->ports[i]))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/tty/CMakeLists.txt b/src/drv/tty/CMakeLists.txt
new file mode 100644
index 0000000..ee14015
--- /dev/null
+++ b/src/drv/tty/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(drv_tty)
+add_subdirectory(src)
+target_include_directories(drv_tty PUBLIC include PRIVATE private_include)
+target_link_libraries(drv_tty PUBLIC c PRIVATE gfx drv_event)
diff --git a/src/drv/tty/include/drv/tty.h b/src/drv/tty/include/drv/tty.h
new file mode 100644
index 0000000..27804bf
--- /dev/null
+++ b/src/drv/tty/include/drv/tty.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_H
+#define DRV_TTY_H
+
+#include <drv/event.h>
+
+struct drv_port *drv_tty_init(const struct drv_event *ev);
+int drv_tty_update(struct drv_port *p);
+void drv_tty_free(struct drv_port *p);
+
+#endif
diff --git a/src/drv/tty/private_include/drv/tty/font.h b/src/drv/tty/private_include/drv/tty/font.h
new file mode 100644
index 0000000..a36d68e
--- /dev/null
+++ b/src/drv/tty/private_include/drv/tty/font.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_FONT_H
+#define DRV_TTY_FONT_H
+
+#include <gfx/sprite.h>
+#include <stddef.h>
+
+struct gfx_sprite ttyfont_spr;
+extern const unsigned char ttyfont[];
+extern const size_t ttyfont_size;
+
+#endif
diff --git a/src/drv/tty/private_include/drv/tty/ops.h b/src/drv/tty/private_include/drv/tty/ops.h
new file mode 100644
index 0000000..b50b00a
--- /dev/null
+++ b/src/drv/tty/private_include/drv/tty/ops.h
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_OPS_H
+#define DRV_TTY_OPS_H
+
+#include <drv/event.h>
+#include <drv/tty/types.h>
+#include <stddef.h>
+
+int drv_tty_write(const void *buf, size_t n, const struct drv_event_done *done,
+ void *args);
+int drv_tty_setdim(struct drv_port *p, unsigned x, unsigned y);
+
+#endif
diff --git a/src/drv/tty/private_include/drv/tty/types.h b/src/drv/tty/private_include/drv/tty/types.h
new file mode 100644
index 0000000..38a1108
--- /dev/null
+++ b/src/drv/tty/private_include/drv/tty/types.h
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRV_TTY_TYPES_H
+#define DRV_TTY_TYPES_H
+
+#include <drv/event.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct row
+{
+ char *columns;
+ size_t len;
+};
+
+struct drv_port
+{
+ bool init;
+ struct row *rows, *first_row, *last_row, *proc_row;
+ size_t nrows, ncolumns, last_column, last_proc_column;
+ struct drv_event ev;
+};
+
+#endif
diff --git a/src/drv/tty/src/CMakeLists.txt b/src/drv/tty/src/CMakeLists.txt
new file mode 100644
index 0000000..096b685
--- /dev/null
+++ b/src/drv/tty/src/CMakeLists.txt
@@ -0,0 +1,27 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_tty PRIVATE
+ free.c
+ init.c
+ setdim.c
+ update.c
+ write.c
+)
+
+if(PS1_BUILD)
+ add_subdirectory(ps1)
+endif()
diff --git a/src/drv/tty/src/free.c b/src/drv/tty/src/free.c
new file mode 100644
index 0000000..66d5cb4
--- /dev/null
+++ b/src/drv/tty/src/free.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void drv_tty_free(struct drv_port *const p)
+{
+ if (!p)
+ return;
+
+ for (size_t i = 0; i < p->nrows; i++)
+ free(p->rows[i].columns);
+
+ free(p->rows);
+ free(p);
+}
diff --git a/src/drv/tty/src/init.c b/src/drv/tty/src/init.c
new file mode 100644
index 0000000..53299f4
--- /dev/null
+++ b/src/drv/tty/src/init.c
@@ -0,0 +1,58 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int load(void *const buf, const size_t n, void *const args)
+{
+ size_t *const off = args;
+
+ memcpy(buf, ttyfont + *off, n);
+ *off += n;
+ return 0;
+}
+
+struct drv_port *drv_tty_init(const struct drv_event *const ev)
+{
+ size_t off = 0;
+ struct drv_port *ret = NULL;
+
+ if (!(ret = malloc(sizeof *ret)))
+ goto failure;
+
+ *ret = (const struct drv_port){.ev = *ev};
+ gfx_sprite_load(&ttyfont_spr, load, &off);
+
+ if (drv_tty_setdim(ret, screen_w, screen_h))
+ goto failure;
+
+ return ret;
+
+failure:
+ drv_tty_free(ret);
+ return NULL;
+}
diff --git a/src/drv/tty/src/ps1/CMakeLists.txt b/src/drv/tty/src/ps1/CMakeLists.txt
new file mode 100644
index 0000000..c07a45f
--- /dev/null
+++ b/src/drv/tty/src/ps1/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(drv_tty PRIVATE
+ ttyfont_tim.c
+)
diff --git a/src/drv/tty/src/ps1/ttyfont_tim.c b/src/drv/tty/src/ps1/ttyfont_tim.c
new file mode 100644
index 0000000..b7dd03b
--- /dev/null
+++ b/src/drv/tty/src/ps1/ttyfont_tim.c
@@ -0,0 +1,801 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* Derived from res/font.bmp. See res/orig/LICENSE for details. */
+
+#include <drv/tty/font.h>
+#include <stddef.h>
+
+const unsigned char ttyfont[] = {
+ 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x80, 0x02, 0xf2, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x7f,
+ 0x2c, 0x34, 0x3e, 0x26, 0xdc, 0x01, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x40, 0x5f, 0x1f, 0x36, 0x9c, 0x03, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x80, 0x00, 0x80, 0x0c, 0x24, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00,
+ 0x30, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x01, 0x01, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x10, 0x01, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x10, 0x11, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x10, 0x00, 0x00, 0x01, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x11,
+ 0x11, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x10, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x10, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x10, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x10, 0x01, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x10, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x10, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x11,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x10, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x10, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x10,
+ 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
+ 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+const size_t ttyfont_size = sizeof ttyfont;
diff --git a/src/drv/tty/src/setdim.c b/src/drv/tty/src/setdim.c
new file mode 100644
index 0000000..d1f835a
--- /dev/null
+++ b/src/drv/tty/src/setdim.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int drv_tty_setdim(struct drv_port *const p, const unsigned w, const unsigned h)
+{
+ const unsigned columns = w / 10, rows = h / 16;
+ struct row *const prs = malloc(rows * sizeof *prs);
+
+ if (!prs)
+ goto failure;
+
+ for (unsigned i = 0; i < rows; i++)
+ *(prs + i) = (const struct row){0};
+
+ for (unsigned i = 0; i < rows; i++)
+ {
+ struct row *const p = &prs[i];
+ char *const c = malloc(columns);
+
+ if (!c)
+ goto failure;
+
+ p->columns = c;
+ }
+
+ p->first_row = p->last_row = p->proc_row = p->rows = prs;
+ p->nrows = rows;
+ p->ncolumns = columns;
+ return 0;
+
+failure:
+ for (unsigned i = 0; i < rows; i++)
+ free(prs[i].columns);
+
+ free(prs);
+ return -1;
+}
diff --git a/src/drv/tty/src/update.backup.c b/src/drv/tty/src/update.backup.c
new file mode 100644
index 0000000..d072977
--- /dev/null
+++ b/src/drv/tty/src/update.backup.c
@@ -0,0 +1,125 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .write = drv_tty_write,
+ .args = p
+ };
+
+ if (ev->status("tty", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+static short get_y(const struct drv_port *const p)
+{
+ const ptrdiff_t r = p->proc_row - p->first_row;
+
+ if (r >= 0)
+ return r * 16;
+
+ return (((p->rows + p->nrows) - p->first_row)
+ + (p->proc_row - p->rows)) * 16;
+}
+
+static int prepare(struct drv_port *const p)
+{
+ struct row *r = p->proc_row;
+
+ if (r == p->last_row)
+ return 0;
+ else if (!p->last_proc_column)
+ {
+ struct gfx_rect *const rect = gfx_rect_get();
+ const short y = get_y(p);
+
+ if (!rect)
+ return 0;
+
+ gfx_rect_init(rect);
+ rect->y = y;
+ rect->w = screen_w;
+ rect->h = 16;
+
+ if (gfx_rect_sort(rect))
+ return -1;
+ }
+
+ const char c = r->columns[p->last_proc_column];
+
+ if (c != ' ')
+ {
+ struct gfx_sprite *const s = gfx_sprite_get();
+
+ if (!s || gfx_sprite_clone(&ttyfont_spr, s))
+ return 0;
+
+ const short x = p->last_proc_column * 10, y = get_y(p);
+ const char ch = c - ' ';
+ const short u = (12 * ch) % ttyfont_spr.w;
+ const short v = 16 * ((12 * ch) / ttyfont_spr.w);
+
+ /* TODO: replace hardcoded values */
+ s->x = x;
+ s->y = y;
+ s->w = 12;
+ s->h = 16;
+ s->u += u;
+ s->v += v;
+
+ if (gfx_sprite_sort(s))
+ return -1;
+ }
+
+ if (++p->last_proc_column >= r->len)
+ {
+ if (++r - p->rows >= p->nrows)
+ r = p->rows;
+
+ p->last_proc_column = 0;
+ }
+
+ p->proc_row = r;
+ return 0;
+}
+
+int drv_tty_update(struct drv_port *const p)
+{
+ if (init(p) || prepare(p))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/tty/src/update.c b/src/drv/tty/src/update.c
new file mode 100644
index 0000000..7c01678
--- /dev/null
+++ b/src/drv/tty/src/update.c
@@ -0,0 +1,126 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/font.h>
+#include <drv/tty/ops.h>
+#include <drv/tty/types.h>
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <stdbool.h>
+
+static int init(struct drv_port *const p)
+{
+ if (p->init)
+ return 0;
+
+ const struct drv_event *const ev = &p->ev;
+ const struct drv_event_ops ops =
+ {
+ .write = drv_tty_write,
+ .args = p
+ };
+
+ if (ev->status("tty", &ops, true, 0666, ev->args))
+ return -1;
+
+ p->init = true;
+ return 0;
+}
+
+static short get_y(const struct drv_port *const p)
+{
+ const ptrdiff_t r = p->proc_row - p->first_row;
+
+ if (r >= 0)
+ return r * 16;
+
+ return (((p->rows + p->nrows) - p->first_row)
+ + (p->proc_row - p->rows)) * 16;
+}
+
+static int prepare(struct drv_port *const p)
+{
+ struct row *r = p->proc_row;
+
+ if (r == p->last_row)
+ return 0;
+
+ struct gfx_rect *const rect = gfx_rect_get();
+ const short y = get_y(p);
+ short x = 0;
+
+ if (!rect)
+ return 0;
+
+ gfx_rect_init(rect);
+ rect->y = y;
+ rect->w = screen_w;
+ rect->h = 16;
+
+ if (gfx_rect_sort(rect))
+ return -1;
+
+ /* TODO: this is a trick to avoid having half-rendered lines. */
+ struct gfx_sprite *sprites[64];
+
+ for (size_t i = 0; i < sizeof sprites / sizeof *sprites; i++)
+ sprites[i] = gfx_sprite_get();
+
+ for (const char *c = r->columns;
+ *c && c - r->columns < p->ncolumns; c++, x += 10)
+ {
+ struct gfx_sprite *const s = sprites[c - r->columns];
+
+ if (*c == ' ')
+ continue;
+
+ const char ch = *c - ' ';
+ const short u = (12 * ch) % ttyfont_spr.w;
+ const short v = 16 * ((12 * ch) / ttyfont_spr.w);
+
+ if (!s || gfx_sprite_clone(&ttyfont_spr, s))
+ return 0;
+
+ /* TODO: replace hardcoded values */
+ s->x = x;
+ s->y = y;
+ s->w = 12;
+ s->h = 16;
+ s->u += u;
+ s->v += v;
+
+ if (gfx_sprite_sort(s))
+ return -1;
+ }
+
+ if (++r - p->rows >= p->nrows)
+ r = p->rows;
+
+ p->proc_row = r;
+ return 0;
+}
+
+int drv_tty_update(struct drv_port *const p)
+{
+ if (init(p) || prepare(p))
+ return -1;
+
+ return 0;
+}
diff --git a/src/drv/tty/src/write.c b/src/drv/tty/src/write.c
new file mode 100644
index 0000000..d4a988d
--- /dev/null
+++ b/src/drv/tty/src/write.c
@@ -0,0 +1,70 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <drv/event.h>
+#include <drv/tty.h>
+#include <drv/tty/types.h>
+#include <drv/tty/ops.h>
+#include <errno.h>
+#include <stddef.h>
+
+int drv_tty_write(const void *const buf, const size_t n,
+ const struct drv_event_done *const d, void *const args)
+{
+ struct drv_port *const p = args;
+
+ for (const char *s = buf; s - (const char *)buf < n; s++)
+ {
+ struct row *const r = p->last_row;
+ char *const col = &r->columns[p->last_column];
+
+ if (*s == '\r')
+ {
+ *col = '\0';
+ p->last_column = r->len = 0;
+ }
+ else
+ {
+ if (*s != '\n')
+ {
+ *col = *s;
+ r->len++;
+ }
+ else
+ *col = '\0';
+
+ if (*s == '\n' || ++p->last_column >= p->ncolumns)
+ {
+ if (++p->last_row - p->rows >= p->nrows)
+ p->last_row = p->rows;
+
+ if (p->last_row == p->first_row)
+ {
+ if (++p->first_row - p->rows >= p->nrows)
+ p->first_row = p->rows;
+
+ p->proc_row = p->first_row;
+ }
+
+ p->last_column = 0;
+ }
+ }
+ }
+
+ return d->f(SUCCESS, d->args);
+}
diff --git a/src/endian/CMakeLists.txt b/src/endian/CMakeLists.txt
new file mode 100644
index 0000000..01a7e98
--- /dev/null
+++ b/src/endian/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(endian)
+add_subdirectory(src)
+target_include_directories(endian PUBLIC include PRIVATE private_include)
diff --git a/src/endian/include/endian.h b/src/endian/include/endian.h
new file mode 100644
index 0000000..7cd0aae
--- /dev/null
+++ b/src/endian/include/endian.h
@@ -0,0 +1,46 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ENDIAN_H
+#define ENDIAN_H
+
+#include <stdint.h>
+
+struct endian_le16
+{
+ uint8_t v[sizeof (uint16_t)];
+};
+
+struct endian_le32
+{
+ uint8_t v[sizeof (uint32_t)];
+};
+
+struct endian_le64
+{
+ uint8_t v[sizeof (uint64_t)];
+};
+
+uint16_t endian_from_le16(const struct endian_le16 *v);
+uint32_t endian_from_le32(const struct endian_le32 *v);
+uint64_t endian_from_le64(const struct endian_le64 *v);
+struct endian_le16 endian_to_le16(uint16_t v);
+struct endian_le32 endian_to_le32(uint32_t v);
+struct endian_le64 endian_to_le64(uint64_t v);
+
+#endif
diff --git a/src/endian/src/CMakeLists.txt b/src/endian/src/CMakeLists.txt
new file mode 100644
index 0000000..962291a
--- /dev/null
+++ b/src/endian/src/CMakeLists.txt
@@ -0,0 +1,24 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(endian PRIVATE
+ from_le16.c
+ from_le32.c
+ from_le64.c
+ to_le16.c
+ to_le32.c
+ to_le64.c
+)
diff --git a/src/endian/src/from_le16.c b/src/endian/src/from_le16.c
new file mode 100644
index 0000000..30685fe
--- /dev/null
+++ b/src/endian/src/from_le16.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <endian.h>
+#include <stdint.h>
+
+uint16_t endian_from_le16(const struct endian_le16 *const v)
+{
+ return v->v[0] | (v->v[1] << 8);
+}
diff --git a/src/endian/src/from_le32.c b/src/endian/src/from_le32.c
new file mode 100644
index 0000000..f56ee7b
--- /dev/null
+++ b/src/endian/src/from_le32.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <endian.h>
+#include <stdint.h>
+
+uint32_t endian_from_le32(const struct endian_le32 *const v)
+{
+ return v->v[0] | (v->v[1] << 8) | ((unsigned long)v->v[2] << 16)
+ | ((unsigned long)v->v[3] << 24);
+}
diff --git a/src/endian/src/from_le64.c b/src/endian/src/from_le64.c
new file mode 100644
index 0000000..37b5f1a
--- /dev/null
+++ b/src/endian/src/from_le64.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <endian.h>
+#include <stdint.h>
+
+uint64_t endian_from_le64(const struct endian_le64 *const v)
+{
+ return v->v[0]
+ | (v->v[1] << 8)
+ | ((uint64_t)v->v[2] << 16ul)
+ | ((uint64_t)v->v[3] << 24ul)
+ | ((uint64_t)v->v[4] << 32ul)
+ | ((uint64_t)v->v[5] << 40ul)
+ | ((uint64_t)v->v[6] << 48ul)
+ | ((uint64_t)v->v[7] << 56ul);
+}
diff --git a/src/endian/src/to_le16.c b/src/endian/src/to_le16.c
new file mode 100644
index 0000000..ddf8faf
--- /dev/null
+++ b/src/endian/src/to_le16.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <endian.h>
+#include <stdint.h>
+
+struct endian_le16 endian_to_le16(const uint16_t v)
+{
+ return (const struct endian_le16)
+ {
+ .v =
+ {
+ [0] = v,
+ [1] = v >> 8
+ }
+ };
+}
diff --git a/src/endian/src/to_le32.c b/src/endian/src/to_le32.c
new file mode 100644
index 0000000..b16dd69
--- /dev/null
+++ b/src/endian/src/to_le32.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <endian.h>
+#include <stdint.h>
+
+struct endian_le32 endian_to_le32(const uint32_t v)
+{
+ return (const struct endian_le32)
+ {
+ .v =
+ {
+ [0] = v,
+ [1] = v >> 8,
+ [2] = v >> 16,
+ [3] = v >> 24
+ }
+ };
+}
diff --git a/src/endian/src/to_le64.c b/src/endian/src/to_le64.c
new file mode 100644
index 0000000..4d1ef1e
--- /dev/null
+++ b/src/endian/src/to_le64.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <endian.h>
+#include <stdint.h>
+
+struct endian_le64 endian_to_le64(const uint64_t v)
+{
+ return (const struct endian_le64)
+ {
+ .v =
+ {
+ [0] = v,
+ [1] = v >> 8,
+ [2] = v >> 16,
+ [3] = v >> 24,
+ [4] = v >> 32,
+ [5] = v >> 40,
+ [6] = v >> 48,
+ [7] = v >> 56,
+ }
+ };
+}
diff --git a/src/fs/CMakeLists.txt b/src/fs/CMakeLists.txt
new file mode 100644
index 0000000..6f4aaea
--- /dev/null
+++ b/src/fs/CMakeLists.txt
@@ -0,0 +1,24 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(fs)
+add_subdirectory(src)
+target_include_directories(fs PUBLIC include PRIVATE private_include)
+target_link_libraries(fs PUBLIC state)
+add_subdirectory(devfs)
+add_subdirectory(iso9660)
+add_subdirectory(ramfs)
+add_subdirectory(rootfs)
diff --git a/src/fs/devfs/CMakeLists.txt b/src/fs/devfs/CMakeLists.txt
new file mode 100644
index 0000000..c3bbcf8
--- /dev/null
+++ b/src/fs/devfs/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(devfs)
+add_subdirectory(src)
+target_include_directories(devfs PUBLIC include PRIVATE private_include)
+target_link_libraries(devfs PUBLIC state c PRIVATE fs drv ramfs)
diff --git a/src/fs/devfs/include/devfs.h b/src/fs/devfs/include/devfs.h
new file mode 100644
index 0000000..ccc82ac
--- /dev/null
+++ b/src/fs/devfs/include/devfs.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DEVFS_H
+#define DEVFS_H
+
+int devfs_register(void);
+
+#endif
diff --git a/src/fs/devfs/private_include/devfs/ops.h b/src/fs/devfs/private_include/devfs/ops.h
new file mode 100644
index 0000000..0c09776
--- /dev/null
+++ b/src/fs/devfs/private_include/devfs/ops.h
@@ -0,0 +1,49 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DEVFS_OPS_H
+#define DEVFS_OPS_H
+
+#include <fs/fs.h>
+#include <drv/event.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+int devfs_mount(const struct fs_mount *m, struct fs_ret *r);
+int devfs_mkdir(const struct fs_mkdir *m, const struct fs_mp *mp,
+ const union inode_result *i, struct fs_ret *r);
+int devfs_open(const struct fs_open *o, const struct fs_mp *mp,
+ const union inode_result *i, struct fs_ret *r);
+int devfs_read(const struct fs_read *r, struct fs_ret *ret);
+int devfs_read_nb(const struct fs_read *r);
+int devfs_write(const struct fs_write *w, struct fs_ret *r);
+int devfs_stat(const struct fs_stat *s, const struct fs_mp *mp,
+ const union inode_result *i, struct fs_ret *r);
+int devfs_close(struct fs_fd *fd);
+int devfs_search(const char *path, const struct fs_mp *mp,
+ union inode_result *inode, struct fs_ret *r);
+int devfs_status(const char *node, const struct drv_event_ops *const ops,
+ bool available, mode_t mode, void *args);
+int devfs_flags(const union inode_result *i);
+int devfs_update(struct fs_mp_prv *pr);
+int devfs_mknod(const char *path, mode_t mode, dev_t dev,
+ const struct drv_event_ops *const ops, struct fs_mp_prv *mp);
+int devfs_unlink(const char *path, struct fs_mp_prv *mp);
+const struct devfs_ops *devfs_ops(const struct fs_mp_prv *pr, const char *node);
+
+#endif
diff --git a/src/fs/devfs/private_include/devfs/types.h b/src/fs/devfs/private_include/devfs/types.h
new file mode 100644
index 0000000..da6b50b
--- /dev/null
+++ b/src/fs/devfs/private_include/devfs/types.h
@@ -0,0 +1,44 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DEVFS_TYPES_H
+#define DEVFS_TYPES_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <drv/drv.h>
+#include <drv/event.h>
+#include <ramfs.h>
+
+struct devfs_ops
+{
+ char *node;
+ struct drv_event_ops ops;
+ struct devfs_ops *prev, *next;
+};
+
+struct fs_mp_prv
+{
+ struct ramfs *rfs;
+ struct drv *drv;
+ struct devfs_ops *head, *tail;
+};
+
+extern const struct fs devfs;
+
+#endif
diff --git a/src/fs/devfs/src/CMakeLists.txt b/src/fs/devfs/src/CMakeLists.txt
new file mode 100644
index 0000000..2a12700
--- /dev/null
+++ b/src/fs/devfs/src/CMakeLists.txt
@@ -0,0 +1,34 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(devfs PRIVATE
+ close.c
+ flags.c
+ mount.c
+ mkdir.c
+ mknod.c
+ open.c
+ ops.c
+ stat.c
+ read.c
+ read_nb.c
+ register.c
+ search.c
+ status.c
+ unlink.c
+ update.c
+ write.c
+)
diff --git a/src/fs/devfs/src/close.c b/src/fs/devfs/src/close.c
new file mode 100644
index 0000000..db236d1
--- /dev/null
+++ b/src/fs/devfs/src/close.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <fs/fs.h>
+
+int devfs_close(struct fs_fd *const fd)
+{
+ return -1;
+}
diff --git a/src/fs/devfs/src/flags.c b/src/fs/devfs/src/flags.c
new file mode 100644
index 0000000..082c5ad
--- /dev/null
+++ b/src/fs/devfs/src/flags.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+
+int devfs_flags(const union inode_result *const i)
+{
+ return i->memi->flags;
+}
diff --git a/src/fs/devfs/src/mkdir.c b/src/fs/devfs/src/mkdir.c
new file mode 100644
index 0000000..cc091e0
--- /dev/null
+++ b/src/fs/devfs/src/mkdir.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+
+int devfs_mkdir(const struct fs_mkdir *m, const struct fs_mp *const mp,
+ const union inode_result *const i, struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/devfs/src/mknod.c b/src/fs/devfs/src/mknod.c
new file mode 100644
index 0000000..f9a369e
--- /dev/null
+++ b/src/fs/devfs/src/mknod.c
@@ -0,0 +1,54 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <fs/inode.h>
+#include <ramfs.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+int devfs_mknod(const char *const node, const mode_t mode, const dev_t dev,
+ const struct drv_event_ops *const ops, struct fs_mp_prv *const pr)
+{
+ struct devfs_ops *dops = NULL;
+ char *const nodedup = strdup(node);
+
+ if (!nodedup
+ || !(dops = malloc(sizeof *dops))
+ || ramfs_mknod(node, mode, dev, pr->rfs))
+ goto failure;
+
+ *dops = (const struct devfs_ops){.node = nodedup, .ops = *ops};
+
+ if (!pr->head)
+ pr->head = dops;
+ else
+ {
+ dops->prev = pr->tail;
+ pr->tail->next = dops;
+ }
+
+ pr->tail = dops;
+ return 0;
+
+failure:
+ free(dops);
+ return -1;
+}
diff --git a/src/fs/devfs/src/mount.c b/src/fs/devfs/src/mount.c
new file mode 100644
index 0000000..2165971
--- /dev/null
+++ b/src/fs/devfs/src/mount.c
@@ -0,0 +1,59 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <drv/drv.h>
+#include <fs/fs.h>
+#include <ramfs.h>
+#include <stdlib.h>
+
+int devfs_mount(const struct fs_mount *const m, struct fs_ret *const r)
+{
+ struct drv *drv = NULL;
+ struct fs_mp_prv *p = NULL;
+ struct ramfs *const rfs = ramfs_mount(m, r);
+
+ if (!rfs || !(p = malloc(sizeof *p)))
+ goto failure;
+
+ const struct drv_event ev =
+ {
+ .status = devfs_status,
+ .args = p
+ };
+
+ if (!(drv = drv_init(&ev))
+ || fs_mountpoint(m->src, m->tgt, &devfs, devfs_update, p))
+ goto failure;
+
+ *p = (const struct fs_mp_prv)
+ {
+ .drv = drv,
+ .rfs = rfs
+ };
+
+ return 0;
+
+failure:
+ drv_free(drv);
+ free(p);
+ ramfs_free(rfs);
+ return -1;
+}
diff --git a/src/fs/devfs/src/open.c b/src/fs/devfs/src/open.c
new file mode 100644
index 0000000..551061f
--- /dev/null
+++ b/src/fs/devfs/src/open.c
@@ -0,0 +1,57 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/types.h>
+#include <devfs/ops.h>
+#include <fs/fs.h>
+#include <state.h>
+#include <stdlib.h>
+
+struct open
+{
+ struct fs_ret *pr, r;
+};
+
+static enum state done(void *const args)
+{
+ struct open *const op = args;
+
+ *op->pr = op->r;
+ free(op);
+ return STATE_AGAIN;
+}
+
+int devfs_open(const struct fs_open *const o, const struct fs_mp *const mp,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ struct open *const op = malloc(sizeof *op);
+
+ if (!op)
+ return -1;
+
+ *op = (const struct open){.pr = r, .r = *r};
+ *o->fd = (const struct fs_fd)
+ {
+ .inode = *inode,
+ .mp = mp
+ };
+
+ *r = (const struct fs_ret){.f = done, .args = op};
+ return 0;
+}
diff --git a/src/fs/devfs/src/ops.c b/src/fs/devfs/src/ops.c
new file mode 100644
index 0000000..c51cfa7
--- /dev/null
+++ b/src/fs/devfs/src/ops.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <string.h>
+
+const struct devfs_ops *devfs_ops(const struct fs_mp_prv *const pr,
+ const char *const node)
+{
+ for (struct devfs_ops *o = pr->head; o; o = o->next)
+ if (!strcmp(o->node, node))
+ return o;
+
+ return NULL;
+}
diff --git a/src/fs/devfs/src/read.c b/src/fs/devfs/src/read.c
new file mode 100644
index 0000000..e968eb2
--- /dev/null
+++ b/src/fs/devfs/src/read.c
@@ -0,0 +1,98 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <fs/fs.h>
+#include <state.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct read
+{
+ bool done;
+ size_t n;
+ struct fs_fd *fd;
+ struct fs_ret *pr, r;
+};
+
+static int done(const int error, void *const args)
+{
+ struct read *const re = args;
+
+ re->done = true;
+ return 0;
+}
+
+static enum state wait(void *const args)
+{
+ struct read *const re = args;
+
+ if (!re->done)
+ return STATE_AGAIN;
+
+ re->fd->offset += re->n;
+ *re->pr = re->r;
+ free(re);
+ return STATE_AGAIN;
+}
+
+int devfs_read(const struct fs_read *const fr, struct fs_ret *const r)
+{
+ struct read *re = NULL;
+ struct fs_fd *const fd = fr->fd;
+ const struct fs_mp *const mp = fd->mp;
+ const struct inode *const inode = fd->inode.memi;
+ const struct devfs_ops *const o = devfs_ops(mp->prv, inode->name);
+
+ if (!o)
+ {
+ errno = ENOENT;
+ goto failure;
+ }
+ else if (!(re = malloc(sizeof *re)))
+ goto failure;
+
+ *re = (const struct read)
+ {
+ .n = fr->n,
+ .fd = fd,
+ .pr = r,
+ .r = *r
+ };
+
+ const struct drv_event_done d =
+ {
+ .f = done,
+ .args = re
+ };
+
+ const struct drv_event_ops *const ops = &o->ops;
+
+ if (ops->read(fr->buf, fr->n, fd->start + fd->offset, &d, ops->args))
+ goto failure;
+
+ *r = (const struct fs_ret){.f = wait, .args = re};
+ return 0;
+
+failure:
+ free(re);
+ return -1;
+}
diff --git a/src/fs/devfs/src/read_nb.c b/src/fs/devfs/src/read_nb.c
new file mode 100644
index 0000000..2f30d5c
--- /dev/null
+++ b/src/fs/devfs/src/read_nb.c
@@ -0,0 +1,41 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <fs/fs.h>
+#include <errno.h>
+
+int devfs_read_nb(const struct fs_read *const fr)
+{
+ struct fs_fd *const fd = fr->fd;
+ const struct fs_mp *const mp = fd->mp;
+ const struct inode *const inode = fd->inode.memi;
+ const struct devfs_ops *const o = devfs_ops(mp->prv, inode->name);
+
+ if (!o)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ const struct drv_event_ops *const ops = &o->ops;
+
+ return ops->read_nb(fr->buf, fr->n, ops->args);
+}
diff --git a/src/fs/devfs/src/register.c b/src/fs/devfs/src/register.c
new file mode 100644
index 0000000..5ff7b33
--- /dev/null
+++ b/src/fs/devfs/src/register.c
@@ -0,0 +1,44 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <fs/fs.h>
+
+const struct fs devfs =
+{
+ .type = "devfs",
+ .mount = devfs_mount,
+ .stat = devfs_stat,
+ .mkdir = devfs_mkdir,
+ .open = devfs_open,
+ .read = devfs_read,
+ .read_nb = devfs_read_nb,
+ .write = devfs_write,
+ .close = devfs_close,
+ .iops =
+ {
+ .search = devfs_search,
+ .flags = devfs_flags
+ }
+};
+
+int devfs_register(void)
+{
+ return fs_register(&devfs);
+}
diff --git a/src/fs/devfs/src/search.c b/src/fs/devfs/src/search.c
new file mode 100644
index 0000000..4360a9f
--- /dev/null
+++ b/src/fs/devfs/src/search.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <fs/fs.h>
+#include <ramfs.h>
+
+int devfs_search(const char *const path, const struct fs_mp *const mp,
+ union inode_result *const inode, struct fs_ret *const r)
+{
+ return ramfs_search(path, mp->prv->rfs, inode, r);
+}
diff --git a/src/fs/devfs/src/stat.c b/src/fs/devfs/src/stat.c
new file mode 100644
index 0000000..50af3ee
--- /dev/null
+++ b/src/fs/devfs/src/stat.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <ramfs.h>
+
+int devfs_stat(const struct fs_stat *const s, const struct fs_mp *const mp,
+ const union inode_result *const i, struct fs_ret *const r)
+{
+ return ramfs_stat(s, mp->prv->rfs, i, r);
+}
diff --git a/src/fs/devfs/src/status.c b/src/fs/devfs/src/status.c
new file mode 100644
index 0000000..fb73c94
--- /dev/null
+++ b/src/fs/devfs/src/status.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs/ops.h>
+#include <drv/event.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+int devfs_status(const char *const node, const struct drv_event_ops *const ops,
+ const bool available, const mode_t mode, void *const args)
+{
+ struct fs_mp_prv *const mp = args;
+
+ return available ? devfs_mknod(node, mode, 0, ops, mp)
+ : devfs_unlink(node, mp);
+}
diff --git a/src/fs/devfs/src/unlink.c b/src/fs/devfs/src/unlink.c
new file mode 100644
index 0000000..3cd87b4
--- /dev/null
+++ b/src/fs/devfs/src/unlink.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs/ops.h>
+#include <sys/types.h>
+#include <errno.h>
+
+int devfs_unlink(const char *const node, struct fs_mp_prv *const mp)
+{
+ return -1;
+}
diff --git a/src/fs/devfs/src/update.c b/src/fs/devfs/src/update.c
new file mode 100644
index 0000000..b437044
--- /dev/null
+++ b/src/fs/devfs/src/update.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/types.h>
+#include <devfs/ops.h>
+#include <drv/drv.h>
+
+int devfs_update(struct fs_mp_prv *const pr)
+{
+ return drv_update(pr->drv);
+}
diff --git a/src/fs/devfs/src/write.c b/src/fs/devfs/src/write.c
new file mode 100644
index 0000000..392666c
--- /dev/null
+++ b/src/fs/devfs/src/write.c
@@ -0,0 +1,95 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <devfs.h>
+#include <devfs/ops.h>
+#include <devfs/types.h>
+#include <fs/fs.h>
+#include <state.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct write
+{
+ bool done;
+ struct fs_fd *fd;
+ struct fs_ret *pr, r;
+};
+
+static int done(const int error, void *const args)
+{
+ struct write *const w = args;
+
+ w->done = true;
+ return 0;
+}
+
+static enum state wait(void *const args)
+{
+ struct write *const w = args;
+
+ if (!w->done)
+ return STATE_AGAIN;
+
+ *w->pr = w->r;
+ free(w);
+ return STATE_AGAIN;
+}
+
+int devfs_write(const struct fs_write *const fw, struct fs_ret *const r)
+{
+ struct fs_fd *const fd = fw->fd;
+ const struct fs_mp *const mp = fd->mp;
+ const struct inode *const inode = fd->inode.memi;
+ const struct devfs_ops *const o = devfs_ops(mp->prv, inode->name);
+ struct write *const w = malloc(sizeof *w);
+
+ if (!w)
+ goto failure;
+ else if (!o)
+ {
+ errno = ENOENT;
+ goto failure;
+ }
+
+ *w = (const struct write)
+ {
+ .fd = fd,
+ .pr = r,
+ .r = *r
+ };
+
+ const struct drv_event_done d =
+ {
+ .f = done,
+ .args = w
+ };
+
+ const struct drv_event_ops *const ops = &o->ops;
+
+ if (ops->write(fw->buf, fw->n, &d, ops->args))
+ goto failure;
+
+ *r = (const struct fs_ret){.f = wait, .args = w};
+ return 0;
+
+failure:
+ free(w);
+ return -1;
+}
diff --git a/src/fs/include/fs/fs.h b/src/fs/include/fs/fs.h
new file mode 100644
index 0000000..aebe1db
--- /dev/null
+++ b/src/fs/include/fs/fs.h
@@ -0,0 +1,146 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef FS_H
+#define FS_H
+
+#include <fs/inode.h>
+#include <state.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct fs_mountpoint;
+struct fs_mp_prv;
+struct fs_fd_prv;
+
+struct fs_stat
+{
+ const char *path;
+ struct stat *sb;
+ uid_t uid;
+ gid_t gid;
+};
+
+struct fs_mkdir
+{
+ const char *path;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+};
+
+struct fs_mount
+{
+ const char *src, *tgt;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+};
+
+struct fs_umount
+{
+ const char *tgt;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+};
+
+struct fs_open
+{
+ const char *path;
+ struct fs_fd *fd;
+ int flags;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+};
+
+struct fs_read
+{
+ struct fs_fd *fd;
+ void *buf;
+ size_t n;
+};
+
+struct fs_write
+{
+ struct fs_fd *fd;
+ const void *buf;
+ size_t n;
+};
+
+struct fs_ret
+{
+ enum state (*f)(void *args);
+ void *args;
+};
+
+enum {FS_DEV_REQUIRED = 1};
+
+struct fs
+{
+ const char *type;
+ int flags;
+ int (*mount)(const struct fs_mount *, struct fs_ret *);
+ int (*umount)(const struct fs_umount *, struct fs_ret *);
+ int (*stat)(const struct fs_stat *, const struct fs_mp *,
+ const union inode_result *, struct fs_ret *);
+ int (*mkdir)(const struct fs_mkdir *, const struct fs_mp *,
+ const union inode_result *, struct fs_ret *);
+ int (*open)(const struct fs_open *, const struct fs_mp *,
+ const union inode_result *, struct fs_ret *);
+ int (*close)(struct fs_fd *);
+ int (*read)(const struct fs_read *, struct fs_ret *);
+ int (*read_nb)(const struct fs_read *);
+ int (*write)(const struct fs_write *, struct fs_ret *);
+ int (*eof)(const struct fs_fd *);
+ struct inode_ops iops;
+};
+
+struct fs_mp
+{
+ const char *src, *tgt;
+ const struct fs *fs;
+ struct fs_mp_prv *prv;
+};
+
+struct fs_fd
+{
+ int error;
+ off_t start, offset, size;
+ struct fs_fd_prv *prv;
+ const struct fs_mp *mp, *tgt_mp;
+ union inode_result inode, tgt_inode;
+};
+
+typedef int (*fs_update_fn)(struct fs_mp_prv *);
+
+int fs_register(const struct fs *fs);
+int fs_update(void);
+int fs_mountpoint(const char *src, const char *tgt, const struct fs *fs,
+ fs_update_fn fn, struct fs_mp_prv *pr);
+const struct fs *fs_from_type(const char *type);
+int fs_mp_from_path(const char *path, struct fs_mp *mp);
+struct fs_mp *fs_mps_from_path(const char *path, size_t *n);
+const char *fs_relpath(const char *path);
+char *fs_parent(const char *path);
+int fs_next(const char *path, char **next, size_t *i);
+
+#endif
diff --git a/src/fs/include/fs/inode.h b/src/fs/include/fs/inode.h
new file mode 100644
index 0000000..fc24d74
--- /dev/null
+++ b/src/fs/include/fs/inode.h
@@ -0,0 +1,81 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef FS_INODE_H
+#define FS_INODE_H
+
+#include <state.h>
+#include <sys/types.h>
+#include <time.h>
+
+struct fs;
+struct fs_mp;
+struct fs_ret;
+struct inode_prv;
+
+enum
+{
+ INODE_DIR = 1,
+ INODE_REGFILE = 1 << 1,
+ INODE_BLOCKDEV = 1 << 2,
+ INODE_MOUNTPOINT = 1 << 3,
+};
+
+struct inode
+{
+ char *name;
+ int flags;
+ ino_t ino;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ off_t size;
+ struct timespec atim, mtim, ctim;
+ struct inode *parent, *child, *left, *right;
+ struct inode_prv *prv;
+ void (*free)(void *);
+};
+
+union inode_result
+{
+ struct inode cachei, *memi;
+};
+
+typedef int (*inode_search_done)(enum state state, const char *relpath,
+ const struct fs_mp *mp, const union inode_result *inode, void *args);
+
+struct inode_search
+{
+ const char *path;
+ inode_search_done done;
+ void *args;
+};
+
+struct inode_ops
+{
+ int (*search)(const char *path, const struct fs_mp *mp,
+ union inode_result *inode, struct fs_ret *r);
+ int (*reserve)(const struct inode *i, void *args, struct fs_ret *r);
+ int (*flags)(const union inode_result *i);
+};
+
+int inode_search(const struct inode_search *s, struct fs_ret *r);
+void inode_search_free(struct inode_search *s);
+void inode_free(struct inode *i);
+
+#endif
diff --git a/src/fs/iso9660/CMakeLists.txt b/src/fs/iso9660/CMakeLists.txt
new file mode 100644
index 0000000..736fc4e
--- /dev/null
+++ b/src/fs/iso9660/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(iso9660)
+add_subdirectory(src)
+target_include_directories(iso9660 PUBLIC include PRIVATE private_include)
+target_link_libraries(iso9660 PUBLIC c PRIVATE fs kprintf state)
diff --git a/src/fs/iso9660/include/iso9660.h b/src/fs/iso9660/include/iso9660.h
new file mode 100644
index 0000000..e7d1864
--- /dev/null
+++ b/src/fs/iso9660/include/iso9660.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ISO9660_H
+#define ISO9660_H
+
+int iso9660_register(void);
+
+#endif
diff --git a/src/fs/iso9660/private_include/iso9660/ops.h b/src/fs/iso9660/private_include/iso9660/ops.h
new file mode 100644
index 0000000..b85d025
--- /dev/null
+++ b/src/fs/iso9660/private_include/iso9660/ops.h
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ISO9660_OPS_H
+#define ISO9660_OPS_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+
+int iso9660_mount(const struct fs_mount *m, struct fs_ret *r);
+int iso9660_mkdir(const struct fs_mkdir *m, const struct fs_mp *mp,
+ const union inode_result *i, struct fs_ret *r);
+int iso9660_open(const struct fs_open *o, const struct fs_mp *mp,
+ const union inode_result *i, struct fs_ret *r);
+int iso9660_read(const struct fs_read *r, struct fs_ret *ret);
+int iso9660_write(const struct fs_write *w, struct fs_ret *r);
+int iso9660_stat(const struct fs_stat *s, const struct fs_mp *mp,
+ const union inode_result *inode, struct fs_ret *r);
+int iso9660_close(struct fs_fd *fd);
+int iso9660_eof(const struct fs_fd *fd);
+int iso9660_search(const char *path, const struct fs_mp *prv,
+ union inode_result *inode, struct fs_ret *r);
+
+#endif
diff --git a/src/fs/iso9660/private_include/iso9660/routines.h b/src/fs/iso9660/private_include/iso9660/routines.h
new file mode 100644
index 0000000..467cce2
--- /dev/null
+++ b/src/fs/iso9660/private_include/iso9660/routines.h
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ISO9660_ROUTINES_H
+#define ISO9660_ROUTINES_H
+
+#include <iso9660/types.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <time.h>
+
+int iso9660_check_header(const struct iso9660_magic *m);
+uint16_t iso9660_lmsb16(const struct iso9660_lmsb16 *p);
+uint32_t iso9660_lmsb32(const struct iso9660_lmsb32 *p);
+int iso9660_totm(const struct iso9660_dt *dt, struct tm *tm);
+int iso9660_totimespec(const struct iso9660_dt *dt, struct timespec *ts);
+int iso9660_etotimespec(const struct iso9660_entry_dt *dt, struct timespec *ts);
+struct tm iso9660_gmtime(const struct iso9660_entry_dt *dt);
+
+#endif
diff --git a/src/fs/iso9660/private_include/iso9660/types.h b/src/fs/iso9660/private_include/iso9660/types.h
new file mode 100644
index 0000000..55544fb
--- /dev/null
+++ b/src/fs/iso9660/private_include/iso9660/types.h
@@ -0,0 +1,148 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ISO9660_TYPES_H
+#define ISO9660_TYPES_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <stdint.h>
+
+#define ISO9660_LE ((const union {int a; char c;}){.a = 1}.c)
+
+struct fs_mp_prv
+{
+ int dummy;
+};
+
+enum
+{
+ ISO9660_TYPE_BOOT_RECORD,
+ ISO9660_TYPE_PRIMARY_VD,
+ ISO9660_TYPE_SUPPLEMENTARY_VD,
+ ISO9660_TYPE_VOLUME_PARTITION,
+ ISO9660_TYPE_TERMINATOR = 0xff,
+};
+
+struct inode_prv
+{
+ long offset;
+};
+
+struct iso9660_magic
+{
+ uint8_t id[sizeof "CD001" - 1];
+};
+
+struct iso9660_header
+{
+ uint8_t type;
+ struct iso9660_magic magic;
+ uint8_t version;
+};
+
+struct iso9660_lmsb16
+{
+ uint8_t le[sizeof (uint16_t)], be[sizeof (uint16_t)];
+};
+
+struct iso9660_lmsb32
+{
+ uint8_t le[sizeof (uint32_t)], be[sizeof (uint32_t)];
+};
+
+struct iso9660_dt
+{
+ char year[sizeof "9999" - 1],
+ month[sizeof "12" - 1],
+ day[sizeof "31" - 1],
+ hour[sizeof "23" - 1],
+ min[sizeof "59" - 1],
+ sec[sizeof "59" - 1],
+ hsec[sizeof "99" - 1];
+ int8_t zone;
+};
+
+struct iso9660_lsb32
+{
+ uint8_t data[sizeof (uint32_t)];
+};
+
+struct iso9660_msb32
+{
+ uint8_t data[sizeof (uint32_t)];
+};
+
+struct iso9660_entry_dt
+{
+ uint8_t year, month, day, hour, min, sec, offset;
+};
+
+enum
+{
+ ISO9660_FLAGS_HIDDEN = 1,
+ ISO9660_FLAGS_DIR = 1 << 1,
+ ISO9660_FLAGS_ASSOC = 1 << 2,
+ ISO9660_FLAGS_HAS_FORMAT = 1 << 3,
+ ISO9660_FLAGS_HAS_UID_GID = 1 << 4,
+ ISO9660_FLAGS_NOT_FINAL = 1 << 7
+};
+
+struct iso9660_entry
+{
+ uint8_t len, attr;
+ struct iso9660_lmsb32 extent_loc, data_len;
+ struct iso9660_entry_dt dt;
+ uint8_t flags;
+ uint8_t funit_sz, interleave_sz;
+ struct iso9660_lmsb16 seq_num;
+ uint8_t id_len;
+};
+
+struct iso9660_pvd
+{
+ uint8_t :8, sysid[32], vid[32], unused[8];
+ struct iso9660_lmsb32 space_size;
+ uint8_t unused_2[32];
+ struct iso9660_lmsb16 set_size, seq_num, block_size;
+ struct iso9660_lmsb32 pathtable_size;
+ struct iso9660_lsb32 lpath_loc, optlpath_loc;
+ struct iso9660_msb32 mpath_loc, optmpath_loc;
+ struct iso9660_entry root_dir;
+ uint8_t padding, set_id[128], pub_id[128], dprep_id[128], app_id[128],
+ copyright_id[37], abstract_id[37], bibl_id[37];
+ struct iso9660_dt creat, mod, exp, eff;
+ uint8_t fs_version, :8, reserved[512 + 653];
+};
+
+
+struct iso9660_vd
+{
+ struct iso9660_header header;
+
+ union
+ {
+ struct iso9660_pvd pvd;
+ } u;
+};
+
+enum {ISO9660_SECTOR_SZ = 2048};
+
+extern const struct fs iso9660;
+
+#endif
diff --git a/src/fs/iso9660/src/CMakeLists.txt b/src/fs/iso9660/src/CMakeLists.txt
new file mode 100644
index 0000000..740e404
--- /dev/null
+++ b/src/fs/iso9660/src/CMakeLists.txt
@@ -0,0 +1,35 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(iso9660 PRIVATE
+ check_header.c
+ close.c
+ eof.c
+ etotimespec.c
+ gmtime.c
+ lmsb16.c
+ lmsb32.c
+ mount.c
+ mkdir.c
+ open.c
+ stat.c
+ read.c
+ register.c
+ search.c
+ totimespec.c
+ totm.c
+ write.c
+)
diff --git a/src/fs/iso9660/src/check_header.c b/src/fs/iso9660/src/check_header.c
new file mode 100644
index 0000000..f504187
--- /dev/null
+++ b/src/fs/iso9660/src/check_header.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/routines.h>
+#include <kprintf.h>
+#include <stdint.h>
+#include <string.h>
+
+int iso9660_check_header(const struct iso9660_magic *const m)
+{
+ static const struct iso9660_magic em = {{'C', 'D', '0', '0', '1'}};
+
+ if (memcmp(m, &em, sizeof *m))
+ {
+ const uint8_t *const b = m->id;
+
+ kprintf("Invalid ISO9660 header: "
+ "{%hhx, %hhx, %hhx, %hhx, %hhx}\n", b[0], b[1], b[2], b[3], b[4]);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/fs/iso9660/src/close.c b/src/fs/iso9660/src/close.c
new file mode 100644
index 0000000..d43da29
--- /dev/null
+++ b/src/fs/iso9660/src/close.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <fs/fs.h>
+
+int iso9660_close(struct fs_fd *const fd)
+{
+ return -1;
+}
diff --git a/src/fs/iso9660/src/eof.c b/src/fs/iso9660/src/eof.c
new file mode 100644
index 0000000..1c36b63
--- /dev/null
+++ b/src/fs/iso9660/src/eof.c
@@ -0,0 +1,33 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <iso9660/types.h>
+#include <fs/inode.h>
+
+int iso9660_eof(const struct fs_fd *const fd)
+{
+ const union inode_result *const i = &fd->tgt_inode;
+ const off_t sz = i->cachei.size;
+
+ if (!sz)
+ return 1;
+
+ return fd->offset >= sz - 1;
+}
diff --git a/src/fs/iso9660/src/etotimespec.c b/src/fs/iso9660/src/etotimespec.c
new file mode 100644
index 0000000..21debf7
--- /dev/null
+++ b/src/fs/iso9660/src/etotimespec.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <time.h>
+
+int iso9660_etotimespec(const struct iso9660_entry_dt *const dt,
+ struct timespec *const ts)
+{
+ struct tm tm = iso9660_gmtime(dt);
+ const time_t t = mktime(&tm);
+
+ if (t == (time_t)-1)
+ return -1;
+
+ *ts = (const struct timespec)
+ {
+ .tv_sec = t,
+ .tv_nsec = 0
+ };
+
+ return 0;
+}
diff --git a/src/fs/iso9660/src/gmtime.c b/src/fs/iso9660/src/gmtime.c
new file mode 100644
index 0000000..2649688
--- /dev/null
+++ b/src/fs/iso9660/src/gmtime.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <time.h>
+
+struct tm iso9660_gmtime(const struct iso9660_entry_dt *const dt)
+{
+ return (const struct tm)
+ {
+ .tm_year = dt->year + 1900,
+ .tm_mon = dt->month,
+ .tm_mday = dt->day,
+ .tm_hour = dt->hour,
+ .tm_min = dt->min,
+ .tm_sec = dt->sec
+ };
+}
diff --git a/src/fs/iso9660/src/lmsb16.c b/src/fs/iso9660/src/lmsb16.c
new file mode 100644
index 0000000..d404b2c
--- /dev/null
+++ b/src/fs/iso9660/src/lmsb16.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <stdint.h>
+#include <string.h>
+
+uint16_t iso9660_lmsb16(const struct iso9660_lmsb16 *const p)
+{
+ const uint16_t *const d = (const void *)(ISO9660_LE ? p->le : p->be);
+ uint16_t ret;
+
+ memcpy(&ret, d, sizeof ret);
+ return ret;
+}
diff --git a/src/fs/iso9660/src/lmsb32.c b/src/fs/iso9660/src/lmsb32.c
new file mode 100644
index 0000000..2811226
--- /dev/null
+++ b/src/fs/iso9660/src/lmsb32.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <stdint.h>
+#include <string.h>
+
+uint32_t iso9660_lmsb32(const struct iso9660_lmsb32 *const p)
+{
+ const uint32_t *const d = (const void *)(ISO9660_LE ? p->le : p->be);
+ uint32_t ret;
+
+ memcpy(&ret, d, sizeof ret);
+ return ret;
+}
diff --git a/src/fs/iso9660/src/mkdir.c b/src/fs/iso9660/src/mkdir.c
new file mode 100644
index 0000000..9d30659
--- /dev/null
+++ b/src/fs/iso9660/src/mkdir.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+
+int iso9660_mkdir(const struct fs_mkdir *const m, const struct fs_mp *const mp,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/iso9660/src/mount.c b/src/fs/iso9660/src/mount.c
new file mode 100644
index 0000000..83e7a6d
--- /dev/null
+++ b/src/fs/iso9660/src/mount.c
@@ -0,0 +1,180 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <fs/fs.h>
+#include <kprintf.h>
+#include <state.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct mount
+{
+ char *src, *tgt;
+ struct fs_fd fd;
+ struct fs_ret *r;
+ struct fs_mount mount;
+ struct iso9660_header header;
+ const struct fs_mp *mp;
+};
+
+static void free_mount(struct mount *const m)
+{
+ if (!m)
+ return;
+
+ m->mp->fs->close(&m->fd);
+ free(m->src);
+ free(m->tgt);
+ free(m);
+}
+
+static enum state check_header(void *const args)
+{
+ enum state ret = STATE_OK;
+ struct mount *const m = args;
+
+ if (iso9660_check_header(&m->header.magic))
+ ret = STATE_FATAL;
+ else if (fs_mountpoint(m->src, m->tgt, &iso9660, NULL, NULL))
+ {
+ kprintf("Failed to allocate mountpoint {source=%s, target=%s}\n",
+ m->src, m->tgt);
+ ret = STATE_FATAL;
+ }
+
+ free_mount(m);
+ return ret;
+}
+
+static enum state read_header(void *const args)
+{
+ struct mount *const m = args;
+ struct fs_fd *const fd = &m->fd;
+ const struct fs *const fs = m->mp->fs;
+ const struct fs_read r =
+ {
+ .buf = &m->header,
+ .n = sizeof m->header,
+ .fd = fd
+ };
+
+ if (fd->error)
+ {
+ errno = fd->error;
+ goto failure;
+ }
+
+ *m->r = (const struct fs_ret)
+ {
+ .f = check_header,
+ .args = m
+ };
+
+ fd->offset = 16 * ISO9660_SECTOR_SZ;
+
+ if (fs->read(&r, m->r))
+ goto failure;
+
+ return STATE_AGAIN;
+
+failure:
+ free_mount(m);
+ return STATE_FATAL;
+}
+
+static int search_done(const enum state state, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct mount *const m = args;
+ const struct fs_mount *const fm = &m->mount;
+
+ if (!inode)
+ {
+ errno = ENOENT;
+ goto failure;
+ }
+
+ const struct fs_open o =
+ {
+ .fd = &m->fd,
+ .gid = fm->gid,
+ .uid = fm->uid,
+ .mode = fm->mode,
+ .path = relpath
+ };
+
+ *m->r = (const struct fs_ret)
+ {
+ .f = read_header,
+ .args = m
+ };
+
+ if (mp->fs->open(&o, mp, inode, m->r))
+ goto failure;
+
+ m->mp = mp;
+ return 0;
+
+failure:
+ free_mount(m);
+ return -1;
+}
+
+int iso9660_mount(const struct fs_mount *const fm, struct fs_ret *const r)
+{
+ char *srcdup = NULL, *tgtdup = NULL;
+ struct mount *const m = malloc(sizeof *m);
+
+ if (!m
+ || !(srcdup = strdup(fm->src))
+ || !(tgtdup = strdup(fm->tgt)))
+ goto failure;
+
+ *m = (const struct mount)
+ {
+ .src = srcdup,
+ .tgt = tgtdup,
+ .mount = *fm,
+ .r = r
+ };
+
+ const struct inode_search s =
+ {
+ .args = m,
+ .path = fm->src,
+ .done = search_done
+ };
+
+ if (inode_search(&s, r))
+ goto failure;
+
+ return 0;
+
+failure:
+ free(srcdup);
+ free(tgtdup);
+ free(m);
+ return -1;
+}
diff --git a/src/fs/iso9660/src/open.c b/src/fs/iso9660/src/open.c
new file mode 100644
index 0000000..1ea6ad7
--- /dev/null
+++ b/src/fs/iso9660/src/open.c
@@ -0,0 +1,107 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct open
+{
+ struct inode inode;
+ struct fs_fd *fd;
+ struct fs_ret *pr, r;
+ const struct fs_mp *mp;
+};
+
+static int search_done(const enum state state, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ int ret = 0;
+ struct open *const op = args;
+ const struct inode *const mpinode = &op->inode;
+ struct fs_fd *const fd = op->fd;
+
+ if (mpinode->flags & INODE_DIR)
+ {
+ fd->error = EISDIR;
+ ret = -1;
+ }
+ else if (state)
+ {
+ fd->error = ENODEV;
+ ret = -1;
+ }
+ else
+ {
+ *fd = (const struct fs_fd)
+ {
+ .start = mpinode->prv->offset,
+ .tgt_inode.cachei = op->inode,
+ .size = mpinode->size,
+ .tgt_mp = op->mp,
+ .inode = *inode,
+ .mp = mp
+ };
+
+ *op->pr = op->r;
+ }
+
+ free(op);
+ return ret;
+}
+
+int iso9660_open(const struct fs_open *const o, const struct fs_mp *const mp,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ const struct inode *const i = &inode->cachei;
+ struct open *const op = malloc(sizeof *op);
+
+ if (!op)
+ return -1;
+
+ const struct inode_search s =
+ {
+ .args = op,
+ .path = mp->src,
+ .done = search_done
+ };
+
+ *op = (const struct open)
+ {
+ .fd = o->fd,
+ .inode = *i,
+ .mp = mp,
+ .pr = r,
+ .r = *r
+ };
+
+ if (inode_search(&s, r))
+ goto failure;
+
+ return 0;
+
+failure:
+ free(op);
+ return -1;
+}
diff --git a/src/fs/iso9660/src/read.c b/src/fs/iso9660/src/read.c
new file mode 100644
index 0000000..6e14845
--- /dev/null
+++ b/src/fs/iso9660/src/read.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int iso9660_read(const struct fs_read *const fr, struct fs_ret *const ret)
+{
+ return -1;
+}
diff --git a/src/fs/iso9660/src/register.c b/src/fs/iso9660/src/register.c
new file mode 100644
index 0000000..70a33f9
--- /dev/null
+++ b/src/fs/iso9660/src/register.c
@@ -0,0 +1,44 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <fs/fs.h>
+
+const struct fs iso9660 =
+{
+ .type = "iso9660",
+ .flags = FS_DEV_REQUIRED,
+ .mount = iso9660_mount,
+ .stat = iso9660_stat,
+ .mkdir = iso9660_mkdir,
+ .open = iso9660_open,
+ .read = iso9660_read,
+ .write = iso9660_write,
+ .close = iso9660_close,
+ .eof = iso9660_eof,
+ .iops =
+ {
+ .search = iso9660_search
+ }
+};
+
+int iso9660_register(void)
+{
+ return fs_register(&iso9660);
+}
diff --git a/src/fs/iso9660/src/search.c b/src/fs/iso9660/src/search.c
new file mode 100644
index 0000000..a7a5150
--- /dev/null
+++ b/src/fs/iso9660/src/search.c
@@ -0,0 +1,557 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <fs/fs.h>
+#include <kprintf.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+struct id
+{
+ char buf[UCHAR_MAX];
+};
+
+struct search
+{
+ union inode_result *inode;
+ const struct fs_mp *src_mp;
+ struct iso9660_entry entry;
+ const char *src, *path;
+ struct fs_ret r, *pr;
+ struct fs_fd fd;
+ off_t offset;
+ size_t token_i;
+ char *token;
+ void *buf;
+ struct id id;
+};
+
+static int prepare_entry(struct search *);
+static int next_entry(struct search *);
+
+static void free_search(struct search *const s)
+{
+ if (!s)
+ return;
+ else if (s->src_mp)
+ s->src_mp->fs->close(&s->fd);
+
+ free(s->buf);
+ free(s->token);
+ free(s);
+}
+
+static int set_inode(struct search *const s,
+ const struct iso9660_entry *const e, const struct id *const id)
+{
+ struct inode *const inode = &s->inode->cachei;
+ struct inode_prv *p = NULL;
+ char *namedup = NULL;
+ struct timespec ts, atim;
+
+ if (clock_gettime(CLOCK_REALTIME, &atim))
+ goto failure;
+ else if (iso9660_etotimespec(&e->dt, &ts))
+ {
+ kprintf("Invalid datetime, path=%s\n", s->path);
+ goto failure;
+ }
+ else if (!(namedup = strdup(id->buf)) || !(p = malloc(sizeof *p)))
+ goto failure;
+
+ *p = (const struct inode_prv)
+ {
+ .offset = iso9660_lmsb32(&e->extent_loc) * ISO9660_SECTOR_SZ
+ };
+
+ *inode = (const struct inode)
+ {
+ .size = iso9660_lmsb32(&e->data_len),
+ .flags = INODE_REGFILE,
+ .name = namedup,
+ .mode = 0555,
+ .atim = atim,
+ .free = free,
+ .ctim = ts,
+ .mtim = ts,
+ .prv = p
+ };
+
+ return 0;
+
+failure:
+ free(p);
+ free(namedup);
+ return -1;
+}
+
+static int next_token(struct search *const s)
+{
+ free(s->token);
+ s->token = NULL;
+
+ if (fs_next(s->path, &s->token, &s->token_i))
+ {
+ kprintf("Failed to extract next token, path=%s, i=%zu\n", s->path,
+ s->token_i);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_version(const char *const version)
+{
+ char *end;
+
+ errno = 0;
+ strtoul(version, &end, 10);
+
+ return errno || *end;
+}
+
+static void extract_id(const char *id, struct id *const out,
+ const char *const ext, const char *const version)
+{
+ char *p = out->buf;
+
+ if (ext)
+ {
+ const ptrdiff_t n = ext - id;
+ const char *const e = ext + 1;
+
+ memcpy(p, id, n);
+ p += n;
+ id += n;
+
+ if (*e)
+ {
+ const ptrdiff_t n = version ? version - e : strlen(e);
+
+ memcpy(p, id, n);
+ p += n;
+ }
+ }
+ else if (version)
+ {
+ memcpy(p, id, version - id);
+ p += version - id;
+ }
+ else
+ {
+ const ptrdiff_t n = strlen(id);
+
+ memcpy(p, id, n);
+ p += n;
+ }
+
+ *p = '\0';
+ p = out->buf;
+
+ while (*p)
+ {
+ *p = tolower(*p);
+ p++;
+ }
+}
+
+static int parse_id(const char *const id, struct id *const out)
+{
+ static const char accept[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+ const char *const ext = strchr(id, '.'), *const version = strchr(id, ';');
+ const size_t n = strspn(id, accept), len = strlen(id);
+
+ /* Ensure only valid characters are met if no version or extension. */
+ if (!version && !ext && n != len)
+ return -1;
+ /* Ensure file version appears only after file extension,
+ * if both are present. */
+ else if (version && ext && ext > version)
+ return -1;
+ /* Ensure one and only one file version and/or extension appear. */
+ else if ((version && strchr(version + 1, ';'))
+ || (ext && strchr(ext + 1, '.')))
+ return -1;
+ else if (version && check_version(version + 1))
+ return -1;
+ /* When present, ensure valid characters only until the file extension
+ * is found. */
+ else if (ext && n != ext - id)
+ return -1;
+
+ extract_id(id, out, ext, version);
+ return 0;
+}
+
+static enum state id_read(void *const args)
+{
+ struct search *volatile const s = args;
+ const struct iso9660_entry *const e = &s->entry;
+ const char *const id = s->id.buf;
+ struct id outid;
+
+ if (!*id || !strcmp(id, "\1"))
+ {
+ if (next_entry(s))
+ goto failure;
+ }
+ else if (parse_id(id, &outid))
+ {
+ kprintf("Invalid file or directory identifier=%s\n", id);
+ goto failure;
+ }
+ else if (!strcmp(outid.buf, s->token))
+ {
+ char *token;
+
+ if (fs_next(s->path, &token, &s->token_i))
+ {
+ kprintf("Failed to extract next token, path=%s, i=%zu\n",
+ s->path, s->token_i);
+ goto failure;
+ }
+ else if (!token)
+ {
+ if (set_inode(s, e, &outid))
+ goto failure;
+
+ *s->pr = s->r;
+ free_search(s);
+ return STATE_AGAIN;
+ }
+ else if (!(e->flags & ISO9660_FLAGS_DIR))
+ {
+ kprintf("Intermediate node %s not a directory, path=%s\n",
+ id, s->path);
+ goto failure;
+ }
+ else
+ {
+ s->fd.offset = iso9660_lmsb32(&e->extent_loc) * ISO9660_SECTOR_SZ;
+
+ if (prepare_entry(s))
+ goto failure;
+ }
+
+ free(s->token);
+ free(s->buf);
+ s->token = token;
+ s->buf = NULL;
+ }
+ else if (next_entry(s))
+ goto failure;
+
+ return STATE_AGAIN;
+
+failure:
+ free_search(s);
+ return STATE_FATAL;
+}
+
+static enum state entry_read(void *const args)
+{
+ struct search *const s = args;
+ const struct iso9660_entry *const e = &s->entry;
+
+ if (e->len < sizeof *e)
+ {
+ kprintf("Unexpected entry length %hhu, expected %zu\n", e->len,
+ sizeof *e);
+ goto failure;
+ }
+
+ char *const buf = s->id.buf;
+ const struct fs_mp *const mp = s->fd.mp;
+ const struct fs_read r =
+ {
+ .buf = buf,
+ .n = e->id_len,
+ .fd = &s->fd
+ };
+
+ *(buf + e->id_len) = '\0';
+ *s->pr = (const struct fs_ret)
+ {
+ .f = id_read,
+ .args = s
+ };
+
+ if (mp->fs->read(&r, s->pr))
+ goto failure;
+
+ return STATE_AGAIN;
+
+failure:
+ free_search(s);
+ return STATE_FATAL;
+}
+
+static int prepare_entry(struct search *const s)
+{
+ const struct fs_read r =
+ {
+ .buf = &s->entry,
+ .fd = &s->fd,
+ .n = sizeof s->entry
+ };
+
+ *s->pr = (const struct fs_ret)
+ {
+ .f = entry_read,
+ .args = s
+ };
+
+ s->offset = s->fd.offset;
+ return s->src_mp->fs->read(&r, s->pr);
+}
+
+static int next_entry(struct search *const s)
+{
+ const struct iso9660_entry *const e = &s->entry;
+ struct fs_fd *const fd = &s->fd;
+
+ fd->offset = s->offset + e->len;
+ return prepare_entry(s);
+}
+
+static int set_root_inode(const struct iso9660_pvd *const pvd,
+ struct search *const s)
+{
+ struct inode *const inode = &s->inode->cachei;
+ struct inode_prv *p = NULL;
+ char *namedup = NULL;
+
+ if (clock_gettime(CLOCK_REALTIME, &inode->atim))
+ goto failure;
+ else if (iso9660_totimespec(&pvd->creat, &inode->ctim))
+ {
+ kprintf("Invalid volume creation time\n");
+ goto failure;
+ }
+ else if (iso9660_totimespec(&pvd->mod, &inode->mtim))
+ {
+ kprintf("Invalid volume modification time\n");
+ goto failure;
+ }
+ else if (!(namedup = strdup("/")) || !(p = malloc(sizeof *p)))
+ goto failure;
+
+ *p = (const struct inode_prv)
+ {
+ .offset = offsetof(struct iso9660_pvd, root_dir)
+ };
+
+ inode->flags = INODE_DIR;
+ inode->mode = 0555;
+ inode->name = namedup;
+ inode->prv = p;
+ *s->pr = s->r;
+ free_search(s);
+ return 0;
+
+failure:
+ free(p);
+ free(namedup);
+ return -1;
+}
+
+static int check_pvd(const struct iso9660_vd *const vd)
+{
+ const struct iso9660_pvd *const pvd = &vd->u.pvd;
+ const struct iso9660_entry *const e = &pvd->root_dir;
+ const struct iso9660_header *const h = &vd->header;
+ const uint16_t block_size = iso9660_lmsb16(&pvd->block_size);
+ const size_t exp_sz = sizeof (struct iso9660_entry) + sizeof pvd->padding;
+
+ if (iso9660_check_header(&h->magic))
+ return -1;
+ else if (h->version != 1)
+ {
+ kprintf("Unsupported ISO9660 version %#hhx, expected 1\n", h->version);
+ return -1;
+ }
+ else if (h->type != ISO9660_TYPE_PRIMARY_VD)
+ {
+ kprintf("Unexpected volume descriptor type %#hhx, expected=%#x\n",
+ h->type, ISO9660_TYPE_PRIMARY_VD);
+ return -1;
+ }
+ else if (pvd->fs_version != 1)
+ {
+ kprintf("Unexpected file structure version %#hhx, expected 1\n",
+ pvd->fs_version);
+ return -1;
+ }
+ else if (block_size != ISO9660_SECTOR_SZ)
+ {
+ kprintf("Unsupported block size %" PRIu16 ", expected %d\n",
+ block_size, ISO9660_SECTOR_SZ);
+ return -1;
+ }
+ else if (e->len != exp_sz)
+ {
+ kprintf("Unexpected root directory length %hhd, expected %zu\n",
+ e->len, exp_sz);
+ return -1;
+ }
+ else if (!(e->flags & ISO9660_FLAGS_DIR))
+ {
+ kprintf("Directory flag (%#hx) not found in file flags (%#hhx)\n",
+ ISO9660_FLAGS_DIR, e->flags);
+ return -1;
+ }
+
+ return 0;
+}
+
+static enum state read_pvd_done(void *const args)
+{
+ struct search *const s = args;
+ struct fs_fd *const fd = &s->fd;
+ const struct iso9660_vd *const vd = s->buf;
+ const struct iso9660_pvd *const pvd = &vd->u.pvd;
+ const struct iso9660_entry *const e = &pvd->root_dir;
+ const uint32_t lba = iso9660_lmsb32(&e->extent_loc);
+
+ fd->offset = lba * ISO9660_SECTOR_SZ;
+
+ if (check_pvd(vd))
+ goto failure;
+ else if (!strcmp(s->src, "/"))
+ {
+ if (set_root_inode(pvd, s))
+ goto failure;
+
+ return STATE_AGAIN;
+ }
+ else if (next_token(s) || prepare_entry(s))
+ goto failure;
+
+ return STATE_AGAIN;
+
+failure:
+ free_search(s);
+ return STATE_FATAL;
+}
+
+static enum state read_pvd(void *const args)
+{
+ struct search *const s = args;
+ struct fs_fd *const fd = &s->fd;
+
+ if (!(s->buf = malloc(ISO9660_SECTOR_SZ)) || next_token(s))
+ goto failure;
+
+ const struct fs_read r =
+ {
+ .buf = s->buf,
+ .fd = fd,
+ .n = ISO9660_SECTOR_SZ
+ };
+
+ *s->pr = (const struct fs_ret)
+ {
+ .f = read_pvd_done,
+ .args = s
+ };
+
+ fd->offset = 16 * ISO9660_SECTOR_SZ;
+
+ if (s->src_mp->fs->read(&r, s->pr))
+ goto failure;
+
+ return STATE_AGAIN;
+
+failure:
+ free_search(s);
+ return STATE_FATAL;
+}
+
+static int src_done(const enum state state, const char *const relpath,
+ const struct fs_mp *const mp, const union inode_result *const inode,
+ void *const args)
+{
+ struct search *const s = args;
+
+ if (state)
+ {
+ kprintf("Failed to find source inode for %s\n", s->src);
+ return -1;
+ }
+
+ s->src_mp = mp;
+ *s->pr = (const struct fs_ret)
+ {
+ .f = read_pvd,
+ .args = s
+ };
+
+ const struct fs_open o =
+ {
+ .fd = &s->fd,
+ .path = mp->src,
+ .flags = O_RDONLY
+ };
+
+ return mp->fs->open(&o, mp, inode, s->pr);
+}
+
+int iso9660_search(const char *const path, const struct fs_mp *const mp,
+ union inode_result *const inode, struct fs_ret *const r)
+{
+ struct search *const s = malloc(sizeof *s);
+
+ if (!s)
+ goto failure;
+
+ *s = (const struct search)
+ {
+ .inode = inode,
+ .src = mp->src,
+ .path = path,
+ .r = *r,
+ .pr = r
+ };
+
+ const struct inode_search is =
+ {
+ .path = mp->src,
+ .done = src_done,
+ .args = s,
+ };
+
+ if (inode_search(&is, r))
+ goto failure;
+
+ return 0;
+
+failure:
+ free(s);
+ return -1;
+}
diff --git a/src/fs/iso9660/src/stat.c b/src/fs/iso9660/src/stat.c
new file mode 100644
index 0000000..53732fe
--- /dev/null
+++ b/src/fs/iso9660/src/stat.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <fs/fs.h>
+#include <sys/stat.h>
+
+int iso9660_stat(const struct fs_stat *const s, const struct fs_mp *const mp,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/iso9660/src/totimespec.c b/src/fs/iso9660/src/totimespec.c
new file mode 100644
index 0000000..735deb7
--- /dev/null
+++ b/src/fs/iso9660/src/totimespec.c
@@ -0,0 +1,54 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int iso9660_totimespec(const struct iso9660_dt *const dt,
+ struct timespec *const ts)
+{
+ char hsec[sizeof dt->hsec + 1], *end;
+ unsigned long v;
+ struct tm tm;
+ time_t t;
+
+ if (iso9660_totm(dt, &tm)
+ || ((t = mktime(&tm)) == (time_t)-1))
+ return -1;
+
+ errno = 0;
+ memcpy(hsec, dt->hsec, sizeof dt->hsec);
+ hsec[sizeof dt->hsec] = '\0';
+ v = strtoul(hsec, &end, 10);
+
+ if (errno || *end || v >= 100)
+ return -1;
+
+ *ts = (const struct timespec)
+ {
+ .tv_sec = t,
+ .tv_nsec = v * 100000ul
+ };
+
+ return 0;
+}
diff --git a/src/fs/iso9660/src/totm.c b/src/fs/iso9660/src/totm.c
new file mode 100644
index 0000000..1e94359
--- /dev/null
+++ b/src/fs/iso9660/src/totm.c
@@ -0,0 +1,72 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/routines.h>
+#include <iso9660/types.h>
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int iso9660_totm(const struct iso9660_dt *const dt, struct tm *const tm)
+{
+ char year[sizeof dt->year + 1],
+ month[sizeof dt->month + 1],
+ day[sizeof dt->day + 1],
+ hour[sizeof dt->hour + 1],
+ min[sizeof dt->min + 1],
+ sec[sizeof dt->sec + 1];
+
+ struct buf
+ {
+ const char *src;
+ char *s;
+ int *v;
+ size_t n;
+ } bufs[] =
+ {
+ {.src = dt->year, .s = year, .n = sizeof dt->year, .v = &tm->tm_year},
+ {.src = dt->month, .s = month, .n = sizeof dt->month, .v = &tm->tm_mon},
+ {.src = dt->day, .s = day, .n = sizeof dt->day, .v = &tm->tm_yday},
+ {.src = dt->hour, .s = hour, .n = sizeof dt->hour, .v = &tm->tm_hour},
+ {.src = dt->min, .s = min, .n = sizeof dt->min, .v = &tm->tm_min},
+ {.src = dt->sec, .s = sec, .n = sizeof dt->sec, .v = &tm->tm_sec}
+ };
+
+ for (size_t i = 0; i < sizeof bufs / sizeof *bufs; i++)
+ {
+ struct buf *const b = &bufs[i];
+ unsigned long v;
+ char *end;
+
+ memcpy(b->s, b->src, b->n - 1);
+ b->s[b->n] = '\0';
+ errno = 0;
+ v = strtoul(b->s, &end, 10);
+
+ if (errno || *end || v > INT_MAX)
+ return -1;
+
+ *b->v = v;
+ }
+
+ return 0;
+}
diff --git a/src/fs/iso9660/src/write.c b/src/fs/iso9660/src/write.c
new file mode 100644
index 0000000..2ce3823
--- /dev/null
+++ b/src/fs/iso9660/src/write.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <iso9660.h>
+#include <iso9660/ops.h>
+#include <fs/fs.h>
+#include <errno.h>
+
+int iso9660_write(const struct fs_write *const w, struct fs_ret *const r)
+{
+ errno = EROFS;
+ return -1;
+}
diff --git a/src/fs/private_include/fs/private.h b/src/fs/private_include/fs/private.h
new file mode 100644
index 0000000..9ccebaf
--- /dev/null
+++ b/src/fs/private_include/fs/private.h
@@ -0,0 +1,63 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef FS_TYPES_H
+#define FS_TYPES_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <state.h>
+#include <sys/types.h>
+
+struct fs_fd_prv;
+
+struct fs_register
+{
+ const struct fs *fs;
+ struct fs_register *next;
+};
+
+struct fs_mountpoint
+{
+ char *src, *tgt;
+ const struct fs *fs;
+ struct fs_mp_prv *prv;
+ struct fs_mountpoint *next;
+ fs_update_fn update;
+};
+
+struct fs_add
+{
+ char *src, *tgt;
+ struct inode_search *search;
+ struct inode *inode;
+ mode_t mode;
+ const struct fs *fs;
+ enum state (*next)(struct fs_add *);
+};
+
+struct fs_fd
+{
+ long off;
+ struct fs_fd_prv *prv;
+};
+
+extern struct fs_register *fs_rhead, *fs_rtail;
+extern struct fs_mountpoint *fs_mphead, *fs_mptail;
+
+#endif
diff --git a/src/fs/private_include/fs/types.h b/src/fs/private_include/fs/types.h
new file mode 100644
index 0000000..e860d77
--- /dev/null
+++ b/src/fs/private_include/fs/types.h
@@ -0,0 +1,55 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef FS_TYPES_H
+#define FS_TYPES_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <state.h>
+#include <sys/types.h>
+
+struct fs_register
+{
+ const struct fs *fs;
+ struct fs_register *next;
+};
+
+struct fs_mountpoint
+{
+ char *src, *tgt;
+ const struct fs *fs;
+ struct fs_mp_prv *prv;
+ struct fs_mountpoint *next;
+ fs_update_fn update;
+};
+
+struct fs_add
+{
+ char *src, *tgt;
+ struct inode_search *search;
+ struct inode *inode;
+ mode_t mode;
+ const struct fs *fs;
+ enum state (*next)(struct fs_add *);
+};
+
+extern struct fs_register *fs_rhead, *fs_rtail;
+extern struct fs_mountpoint *fs_mphead, *fs_mptail;
+
+#endif
diff --git a/src/fs/ramfs/CMakeLists.txt b/src/fs/ramfs/CMakeLists.txt
new file mode 100644
index 0000000..477e8a7
--- /dev/null
+++ b/src/fs/ramfs/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(ramfs)
+add_subdirectory(src)
+target_include_directories(ramfs PUBLIC include PRIVATE private_include)
+target_link_libraries(ramfs PUBLIC state c PRIVATE fs drv)
diff --git a/src/fs/ramfs/include/ramfs.h b/src/fs/ramfs/include/ramfs.h
new file mode 100644
index 0000000..74160e1
--- /dev/null
+++ b/src/fs/ramfs/include/ramfs.h
@@ -0,0 +1,43 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef RAMFS_H
+#define RAMFS_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+struct ramfs *ramfs_mount(const struct fs_mount *m, struct fs_ret *r);
+int ramfs_mkdir(const struct fs_mkdir *m, struct ramfs *rfs,
+ const union inode_result *i, struct fs_ret *r);
+int ramfs_open(const struct fs_open *o, struct inode *i, struct fs_ret *r);
+int ramfs_read(const struct fs_read *r, struct fs_ret *ret);
+int ramfs_write(const struct fs_write *w, struct fs_ret *r);
+int ramfs_stat(const struct fs_stat *s, const struct ramfs *rfs,
+ const union inode_result *inode, struct fs_ret *r);
+int ramfs_close(struct fs_fd *fd);
+int ramfs_search(const char *path, const struct ramfs *rfs,
+ union inode_result *inode, struct fs_ret *r);
+int ramfs_flags(const union inode_result *i);
+int ramfs_mknod(const char *node, mode_t mode, dev_t dev, struct ramfs *rfs);
+void ramfs_free(struct ramfs *rfs);
+
+#endif
diff --git a/src/fs/ramfs/private_include/ramfs/types.h b/src/fs/ramfs/private_include/ramfs/types.h
new file mode 100644
index 0000000..9be5899
--- /dev/null
+++ b/src/fs/ramfs/private_include/ramfs/types.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef RAMFS_TYPES_H
+#define RAMFS_TYPES_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+
+struct ramfs
+{
+ struct inode *root;
+ ino_t ino;
+};
+
+#endif
diff --git a/src/fs/ramfs/src/CMakeLists.txt b/src/fs/ramfs/src/CMakeLists.txt
new file mode 100644
index 0000000..a35e23e
--- /dev/null
+++ b/src/fs/ramfs/src/CMakeLists.txt
@@ -0,0 +1,29 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(ramfs PRIVATE
+ close.c
+ free.c
+ flags.c
+ mount.c
+ mkdir.c
+ mknod.c
+ open.c
+ stat.c
+ read.c
+ search.c
+ write.c
+)
diff --git a/src/fs/ramfs/src/close.c b/src/fs/ramfs/src/close.c
new file mode 100644
index 0000000..5243a77
--- /dev/null
+++ b/src/fs/ramfs/src/close.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <fs/fs.h>
+
+int ramfs_close(struct fs_fd *const fd)
+{
+ return -1;
+}
diff --git a/src/fs/ramfs/src/flags.c b/src/fs/ramfs/src/flags.c
new file mode 100644
index 0000000..7f51b81
--- /dev/null
+++ b/src/fs/ramfs/src/flags.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <fs/inode.h>
+
+int ramfs_flags(const union inode_result *const i)
+{
+ return i->memi->flags;
+}
diff --git a/src/fs/ramfs/src/free.c b/src/fs/ramfs/src/free.c
new file mode 100644
index 0000000..10fcbd6
--- /dev/null
+++ b/src/fs/ramfs/src/free.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <ramfs/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void ramfs_free(struct ramfs *const r)
+{
+ if (!r)
+ return;
+
+ inode_free(r->root);
+ free(r);
+}
diff --git a/src/fs/ramfs/src/mkdir.c b/src/fs/ramfs/src/mkdir.c
new file mode 100644
index 0000000..f62984d
--- /dev/null
+++ b/src/fs/ramfs/src/mkdir.c
@@ -0,0 +1,79 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <ramfs/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <state.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static enum state done(void *const args)
+{
+ return STATE_OK;
+}
+
+int ramfs_mkdir(const struct fs_mkdir *const m, struct ramfs *const rfs,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ struct timespec ts;
+ struct inode *ni = NULL;
+ struct inode *const parent = inode->memi;
+ char *const name = strdup(m->path);
+
+ if (!name
+ || clock_gettime(CLOCK_REALTIME, &ts)
+ || !(ni = malloc(sizeof *ni)))
+ goto failure;
+
+ *ni = (const struct inode)
+ {
+ .name = name,
+ .mode = m->mode,
+ .uid = m->uid,
+ .gid = m->gid,
+ .flags = INODE_DIR,
+ .atim = ts,
+ .ctim = ts,
+ .mtim = ts,
+ .ino = rfs->ino++,
+ .parent = parent
+ };
+
+ if (!parent->child)
+ parent->child = ni;
+ else
+ for (struct inode *i = parent->child; i; i = i->right)
+ if (!i->right)
+ {
+ i->right = ni;
+ ni->left = i;
+ break;
+ }
+
+ parent->atim = parent->mtim = ts;
+ *r = (const struct fs_ret){.f = done};
+ return 0;
+
+failure:
+ free(ni);
+ free(name);
+ return -1;
+}
diff --git a/src/fs/ramfs/src/mknod.c b/src/fs/ramfs/src/mknod.c
new file mode 100644
index 0000000..d142ab1
--- /dev/null
+++ b/src/fs/ramfs/src/mknod.c
@@ -0,0 +1,87 @@
+
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <ramfs/types.h>
+#include <fs/inode.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static struct inode *find(const char *const node, struct inode *const root)
+{
+ for (struct inode *c = root->child; c; c = c->right)
+ if (!strcmp(c->name, node))
+ return c;
+
+ return NULL;
+}
+
+int ramfs_mknod(const char *const node, const mode_t mode, const dev_t dev,
+ struct ramfs *const rfs)
+{
+ struct inode *const r = rfs->root,
+ *const inode = find(node, r),
+ *newinode = NULL;
+ char *nodedup = NULL;
+ struct timespec ts;
+
+ if (inode)
+ {
+ errno = EEXIST;
+ goto failure;
+ }
+ else if (clock_gettime(CLOCK_REALTIME, &ts)
+ || !(nodedup = strdup(node))
+ || !(newinode = malloc(sizeof *newinode)))
+ goto failure;
+
+ *newinode = (const struct inode)
+ {
+ .atim = ts,
+ .ctim = ts,
+ .mtim = ts,
+ .flags = INODE_BLOCKDEV,
+ .mode = mode,
+ .parent = rfs->root,
+ .name = nodedup
+ };
+
+ if (!r->child)
+ r->child = newinode;
+ else
+ for (struct inode *c = r->child; c; c = c->right)
+ if (!c->right)
+ {
+ c->right = newinode;
+ newinode->left = c;
+ break;
+ }
+
+ r->atim = r->mtim = ts;
+ return 0;
+
+failure:
+ free(nodedup);
+ free(newinode);
+ return -1;
+}
diff --git a/src/fs/ramfs/src/mount.c b/src/fs/ramfs/src/mount.c
new file mode 100644
index 0000000..567c2da
--- /dev/null
+++ b/src/fs/ramfs/src/mount.c
@@ -0,0 +1,69 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <ramfs/types.h>
+#include <fs/fs.h>
+#include <state.h>
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static enum state mount(void *const args)
+{
+ return STATE_OK;
+}
+
+struct ramfs *ramfs_mount(const struct fs_mount *const m,
+ struct fs_ret *const r)
+{
+ struct ramfs *ret = NULL;
+ struct timespec ts;
+ char *const name = strdup("/");
+ struct inode *root = NULL;
+
+ if (!name
+ || clock_gettime(CLOCK_REALTIME, &ts)
+ || !(root = malloc(sizeof *root))
+ || !(ret = malloc(sizeof *ret)))
+ goto failure;
+
+ *root = (const struct inode)
+ {
+ .name = name,
+ .mode = m->mode,
+ .uid = m->uid,
+ .gid = m->gid,
+ .atim = ts,
+ .mtim = ts,
+ .ctim = ts
+ };
+
+ *ret = (const struct ramfs){.root = root};
+ *r = (const struct fs_ret){.f = mount};
+ ret->ino++;
+ return ret;
+
+failure:
+ free(root);
+ free(ret);
+ free(name);
+ return NULL;
+}
diff --git a/src/fs/ramfs/src/open.c b/src/fs/ramfs/src/open.c
new file mode 100644
index 0000000..894b160
--- /dev/null
+++ b/src/fs/ramfs/src/open.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <fs/fs.h>
+
+int ramfs_open(const struct fs_open *const o,struct inode *const i,
+ struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/ramfs/src/read.c b/src/fs/ramfs/src/read.c
new file mode 100644
index 0000000..cc96744
--- /dev/null
+++ b/src/fs/ramfs/src/read.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int ramfs_read(const struct fs_read *const r, struct fs_ret *const ret)
+{
+ return -1;
+}
diff --git a/src/fs/ramfs/src/search.c b/src/fs/ramfs/src/search.c
new file mode 100644
index 0000000..24e2a98
--- /dev/null
+++ b/src/fs/ramfs/src/search.c
@@ -0,0 +1,143 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <ramfs/types.h>
+#include <fs/fs.h>
+#include <state.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct search
+{
+ union inode_result *inode;
+ const struct ramfs *rfs;
+ struct fs_ret r, *pr;
+ const char *path;
+};
+
+static void free_search(struct search *const s)
+{
+ free(s);
+}
+
+static int find_node(const char *const path, struct inode **const out,
+ size_t *const i)
+{
+ int ret = -1;
+ char *node;
+ struct inode *volatile const inode = *out;
+
+ if (fs_next(path, &node, i))
+ return -1;
+ else if (!strcmp(inode->name, node))
+ {
+ if (*i >= strlen(path))
+ {
+ free(node);
+ return 1;
+ }
+
+ *out = inode->child;
+ }
+ else
+ {
+ bool found = false;
+
+ for (struct inode *in = inode->right; in; in = in->right)
+ if (!strcmp(in->name, node))
+ {
+ if (*i >= strlen(path))
+ {
+ *out = in;
+ free(node);
+ return 1;
+ }
+
+ *out = in->child;
+ found = true;
+ break;
+ }
+
+ if (!found)
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ free(node);
+ return ret;
+}
+
+static enum state search(void *const args)
+{
+ enum state ret = STATE_FATAL;
+ struct search *const s = args;
+ struct inode *inode = s->rfs->root;
+ size_t i = 0;
+
+ for (;;)
+ {
+ const int n = find_node(s->path, &inode, &i);
+
+ if (n < 0)
+ goto end;
+ else if (n > 0)
+ break;
+ }
+
+ s->inode->memi = inode;
+ *s->pr = s->r;
+ ret = STATE_AGAIN;
+
+end:
+ free_search(s);
+ return ret;
+}
+
+int ramfs_search(const char *const path, const struct ramfs *const rfs,
+ union inode_result *const inode, struct fs_ret *const r)
+{
+ struct search *const s = malloc(sizeof *s);
+
+ if (!s)
+ goto failure;
+
+ *s = (const struct search)
+ {
+ .inode = inode,
+ .path = path,
+ .rfs = rfs,
+ .r = *r,
+ .pr = r
+ };
+
+ *r = (const struct fs_ret)
+ {
+ .f = search,
+ .args = s
+ };
+
+ return 0;
+
+failure:
+ free(s);
+ return -1;
+}
diff --git a/src/fs/ramfs/src/stat.c b/src/fs/ramfs/src/stat.c
new file mode 100644
index 0000000..6bb1b23
--- /dev/null
+++ b/src/fs/ramfs/src/stat.c
@@ -0,0 +1,53 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <fs/fs.h>
+#include <state.h>
+#include <sys/stat.h>
+
+static enum state done(void *const args)
+{
+ return STATE_OK;
+}
+
+int ramfs_stat(const struct fs_stat *const s, const struct ramfs *const rfs,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ const struct inode *const i = inode->memi;
+
+ *s->sb = (const struct stat)
+ {
+ .st_atim = i->atim,
+ .st_ctim = i->ctim,
+ .st_mtim = i->mtim,
+ .st_size = i->size,
+ .st_blksize = 1,
+ .st_ino = i->ino,
+ .st_uid = i->uid,
+ .st_gid = i->gid,
+ .st_mode = i->mode
+ };
+
+ *r = (const struct fs_ret)
+ {
+ .f = done
+ };
+
+ return 0;
+}
diff --git a/src/fs/ramfs/src/write.c b/src/fs/ramfs/src/write.c
new file mode 100644
index 0000000..ca49c22
--- /dev/null
+++ b/src/fs/ramfs/src/write.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ramfs.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int ramfs_write(const struct fs_write *const w, struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/rootfs/CMakeLists.txt b/src/fs/rootfs/CMakeLists.txt
new file mode 100644
index 0000000..588d14b
--- /dev/null
+++ b/src/fs/rootfs/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(rootfs)
+add_subdirectory(src)
+target_include_directories(rootfs PUBLIC include PRIVATE private_include)
+target_link_libraries(rootfs PUBLIC state c PRIVATE fs ramfs)
diff --git a/src/fs/rootfs/include/rootfs.h b/src/fs/rootfs/include/rootfs.h
new file mode 100644
index 0000000..2327079
--- /dev/null
+++ b/src/fs/rootfs/include/rootfs.h
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ROOTFS_H
+#define ROOTFS_H
+
+int rootfs_register(void);
+
+#endif
diff --git a/src/fs/rootfs/private_include/rootfs/ops.h b/src/fs/rootfs/private_include/rootfs/ops.h
new file mode 100644
index 0000000..decdf8b
--- /dev/null
+++ b/src/fs/rootfs/private_include/rootfs/ops.h
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ROOTFS_OPS_H
+#define ROOTFS_OPS_H
+
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+int rootfs_mount(const struct fs_mount *m, struct fs_ret *r);
+int rootfs_mkdir(const struct fs_mkdir *m, const struct fs_mp *mp,
+ const union inode_result *i, struct fs_ret *r);
+int rootfs_open(const struct fs_open *o, const struct fs_mp *mp,
+ const union inode_result *i, struct fs_ret *r);
+int rootfs_read(const struct fs_read *r, struct fs_ret *ret);
+int rootfs_write(const struct fs_write *w, struct fs_ret *r);
+int rootfs_stat(const struct fs_stat *s, const struct fs_mp *mp,
+ const union inode_result *inode, struct fs_ret *r);
+int rootfs_close(struct fs_fd *fd);
+int rootfs_search(const char *path, const struct fs_mp *mp,
+ union inode_result *inode, struct fs_ret *r);
+int rootfs_flags(const union inode_result *i);
+
+#endif
diff --git a/src/fs/rootfs/private_include/rootfs/types.h b/src/fs/rootfs/private_include/rootfs/types.h
new file mode 100644
index 0000000..471d9d3
--- /dev/null
+++ b/src/fs/rootfs/private_include/rootfs/types.h
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef ROOTFS_TYPES_H
+#define ROOTFS_TYPES_H
+
+#include <fs/fs.h>
+#include <ramfs.h>
+
+struct fs_mp_prv
+{
+ struct ramfs *rfs;
+};
+
+extern const struct fs rootfs;
+
+#endif
diff --git a/src/fs/rootfs/src/CMakeLists.txt b/src/fs/rootfs/src/CMakeLists.txt
new file mode 100644
index 0000000..8e295e1
--- /dev/null
+++ b/src/fs/rootfs/src/CMakeLists.txt
@@ -0,0 +1,28 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(rootfs PRIVATE
+ close.c
+ flags.c
+ mount.c
+ mkdir.c
+ open.c
+ stat.c
+ read.c
+ register.c
+ search.c
+ write.c
+)
diff --git a/src/fs/rootfs/src/close.c b/src/fs/rootfs/src/close.c
new file mode 100644
index 0000000..1704e48
--- /dev/null
+++ b/src/fs/rootfs/src/close.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <fs/fs.h>
+
+int rootfs_close(struct fs_fd *const fd)
+{
+ return -1;
+}
diff --git a/src/fs/rootfs/src/flags.c b/src/fs/rootfs/src/flags.c
new file mode 100644
index 0000000..5a0d5a6
--- /dev/null
+++ b/src/fs/rootfs/src/flags.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <rootfs/ops.h>
+#include <fs/inode.h>
+
+int rootfs_flags(const union inode_result *const i)
+{
+ return i->memi->flags;
+}
diff --git a/src/fs/rootfs/src/mkdir.c b/src/fs/rootfs/src/mkdir.c
new file mode 100644
index 0000000..5f4118f
--- /dev/null
+++ b/src/fs/rootfs/src/mkdir.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <rootfs/ops.h>
+#include <rootfs/types.h>
+#include <fs/fs.h>
+#include <fs/inode.h>
+#include <ramfs.h>
+
+int rootfs_mkdir(const struct fs_mkdir *const m, const struct fs_mp *const mp,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ return ramfs_mkdir(m, mp->prv->rfs, inode, r);
+}
diff --git a/src/fs/rootfs/src/mount.c b/src/fs/rootfs/src/mount.c
new file mode 100644
index 0000000..4ef6258
--- /dev/null
+++ b/src/fs/rootfs/src/mount.c
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <rootfs/types.h>
+#include <ramfs.h>
+#include <fs/fs.h>
+#include <stdlib.h>
+
+int rootfs_mount(const struct fs_mount *const m, struct fs_ret *const r)
+{
+ struct ramfs *rfs = NULL;
+ struct fs_mp_prv *const p = malloc(sizeof *p);
+
+ if (!p
+ || !(rfs = ramfs_mount(m, r))
+ || fs_mountpoint(m->src, m->tgt, &rootfs, NULL, p))
+ goto failure;
+
+ *p = (const struct fs_mp_prv){.rfs = rfs};
+ return 0;
+
+failure:
+ ramfs_free(rfs);
+ free(p);
+ return -1;
+}
diff --git a/src/fs/rootfs/src/open.c b/src/fs/rootfs/src/open.c
new file mode 100644
index 0000000..4a88f41
--- /dev/null
+++ b/src/fs/rootfs/src/open.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <rootfs/ops.h>
+#include <fs/fs.h>
+
+int rootfs_open(const struct fs_open *const o, const struct fs_mp *const mp,
+ const union inode_result *const i, struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/rootfs/src/read.c b/src/fs/rootfs/src/read.c
new file mode 100644
index 0000000..50fe963
--- /dev/null
+++ b/src/fs/rootfs/src/read.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int rootfs_read(const struct fs_read *const r, struct fs_ret *const ret)
+{
+ return -1;
+}
diff --git a/src/fs/rootfs/src/register.c b/src/fs/rootfs/src/register.c
new file mode 100644
index 0000000..02032d8
--- /dev/null
+++ b/src/fs/rootfs/src/register.c
@@ -0,0 +1,43 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <rootfs/ops.h>
+#include <fs/fs.h>
+
+const struct fs rootfs =
+{
+ .type = "rootfs",
+ .mount = rootfs_mount,
+ .stat = rootfs_stat,
+ .mkdir = rootfs_mkdir,
+ .open = rootfs_open,
+ .read = rootfs_read,
+ .write = rootfs_write,
+ .close = rootfs_close,
+ .iops =
+ {
+ .search = rootfs_search,
+ .flags = rootfs_flags
+ }
+};
+
+int rootfs_register(void)
+{
+ return fs_register(&rootfs);
+}
diff --git a/src/fs/rootfs/src/search.c b/src/fs/rootfs/src/search.c
new file mode 100644
index 0000000..269f5d0
--- /dev/null
+++ b/src/fs/rootfs/src/search.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <rootfs/ops.h>
+#include <rootfs/types.h>
+#include <fs/fs.h>
+#include <ramfs.h>
+
+int rootfs_search(const char *const path, const struct fs_mp *const mp,
+ union inode_result *const inode, struct fs_ret *const r)
+{
+ return ramfs_search(path, mp->prv->rfs, inode, r);
+}
diff --git a/src/fs/rootfs/src/stat.c b/src/fs/rootfs/src/stat.c
new file mode 100644
index 0000000..1561190
--- /dev/null
+++ b/src/fs/rootfs/src/stat.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <rootfs/ops.h>
+#include <fs/fs.h>
+#include <sys/stat.h>
+
+int rootfs_stat(const struct fs_stat *const s, const struct fs_mp *const mp,
+ const union inode_result *const inode, struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/rootfs/src/write.c b/src/fs/rootfs/src/write.c
new file mode 100644
index 0000000..874e40c
--- /dev/null
+++ b/src/fs/rootfs/src/write.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <rootfs.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int rootfs_write(const struct fs_write *const w, struct fs_ret *const r)
+{
+ return -1;
+}
diff --git a/src/fs/src/CMakeLists.txt b/src/fs/src/CMakeLists.txt
new file mode 100644
index 0000000..efeb0f1
--- /dev/null
+++ b/src/fs/src/CMakeLists.txt
@@ -0,0 +1,30 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(fs PRIVATE
+ from_type.c
+ headtail.c
+ mountpoint.c
+ mp_from_path.c
+ mps_from_path.c
+ parent.c
+ register.c
+ relpath.c
+ update.c
+ next.c
+)
+
+add_subdirectory(inode)
diff --git a/src/fs/src/from_type.c b/src/fs/src/from_type.c
new file mode 100644
index 0000000..360384b
--- /dev/null
+++ b/src/fs/src/from_type.c
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+const struct fs *fs_from_type(const char *const type)
+{
+ for (const struct fs_register *r = fs_rhead; r; r = r->next)
+ {
+ const struct fs *const fs = r->fs;
+
+ if (!strcmp(type, fs->type))
+ return fs;
+ }
+
+ return NULL;
+}
diff --git a/src/fs/src/headtail.c b/src/fs/src/headtail.c
new file mode 100644
index 0000000..9df580f
--- /dev/null
+++ b/src/fs/src/headtail.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/types.h>
+
+struct fs_register *fs_rhead, *fs_rtail;
+struct fs_mountpoint *fs_mphead, *fs_mptail;
diff --git a/src/fs/src/inode/CMakeLists.txt b/src/fs/src/inode/CMakeLists.txt
new file mode 100644
index 0000000..350dd71
--- /dev/null
+++ b/src/fs/src/inode/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(fs PRIVATE
+ free.c
+ search.c
+)
diff --git a/src/fs/src/inode/free.c b/src/fs/src/inode/free.c
new file mode 100644
index 0000000..3eca47d
--- /dev/null
+++ b/src/fs/src/inode/free.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/inode.h>
+#include <stdlib.h>
+
+void inode_free(struct inode *const i)
+{
+ if (i)
+ {
+ inode_free(i->child);
+ free(i->name);
+
+ if (i->free)
+ i->free(i->prv);
+ }
+
+ free(i);
+}
diff --git a/src/fs/src/inode/search.c b/src/fs/src/inode/search.c
new file mode 100644
index 0000000..4715dd2
--- /dev/null
+++ b/src/fs/src/inode/search.c
@@ -0,0 +1,121 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/inode.h>
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <state.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct search
+{
+ struct fs_mp *mp;
+ size_t n, mp_i;
+ struct fs_ret *r;
+ union inode_result inode;
+ struct inode_search search;
+};
+
+static void free_search(struct search *const s)
+{
+ free(s);
+}
+
+static enum state search_mp(struct search *const s)
+{
+ const struct inode_search *const is = &s->search;
+ const struct fs_mp *const cur = &s->mp[s->mp_i],
+ *const next = s->mp_i + 1 < s->n ?
+ &s->mp[s->mp_i + 1] : NULL;
+ const struct fs *const fs = cur->fs;
+ const char *relpath = next ? next->tgt : is->path;
+
+ for (size_t i = 0; i < s->mp_i; i++)
+ relpath += strlen(s->mp[s->mp_i].tgt);
+
+ if (fs && fs->iops.search(relpath, cur, &s->inode, s->r))
+ return STATE_FATAL;
+
+ s->mp_i++;
+ return STATE_AGAIN;
+}
+
+static enum state search(void *const args)
+{
+ struct search *const s = args;
+ const struct inode_search *const is = &s->search;
+
+ if (!s->mp)
+ {
+ const int ret = is->done(STATE_FATAL, NULL, NULL, NULL, is->args);
+
+ free_search(s);
+ return ret ? STATE_FATAL : STATE_AGAIN;
+ }
+ else if (s->mp_i < s->n)
+ return search_mp(s);
+ else
+ {
+ const char *relpath = is->path;
+
+ for (size_t i = 0; i < s->n; i++)
+ relpath += strlen(s->mp[i].tgt);
+
+ const int ret = is->done(STATE_OK, relpath, &s->mp[s->n - 1],
+ &s->inode, is->args);
+
+ free_search(s);
+ return ret ? STATE_FATAL : STATE_AGAIN;
+ }
+
+ return STATE_FATAL;
+}
+
+int inode_search(const struct inode_search *const is, struct fs_ret *const r)
+{
+ struct search *s = NULL;
+ size_t n;
+ /* TODO: do not check for errors yet. */
+ struct fs_mp *const mp = fs_mps_from_path(is->path, &n);
+
+ if (!(s = malloc(sizeof *s)))
+ goto failure;
+
+ *s = (const struct search)
+ {
+ .search = *is,
+ .mp = mp,
+ .n = n,
+ .r = r
+ };
+
+ *r = (const struct fs_ret)
+ {
+ .f = search,
+ .args = s
+ };
+
+ return 0;
+
+failure:
+ free(s);
+ free(mp);
+ return -1;
+}
diff --git a/src/fs/src/mountpoint.c b/src/fs/src/mountpoint.c
new file mode 100644
index 0000000..32b6ea9
--- /dev/null
+++ b/src/fs/src/mountpoint.c
@@ -0,0 +1,60 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+int fs_mountpoint(const char *const src, const char *const tgt,
+ const struct fs *const fs, const fs_update_fn fn,
+ struct fs_mp_prv *const pr)
+{
+ struct fs_mountpoint *m = NULL;
+ char *srcdup = NULL, *const tgtdup = strdup(tgt);
+
+ if (!tgtdup)
+ goto failure;
+ else if (src && !(srcdup = strdup(src)))
+ goto failure;
+ else if (!(m = malloc(sizeof *m)))
+ goto failure;
+
+ *m = (const struct fs_mountpoint)
+ {
+ .src = srcdup,
+ .tgt = tgtdup,
+ .update = fn,
+ .fs = fs,
+ .prv = pr
+ };
+
+ if (!fs_mphead)
+ fs_mphead = m;
+ else if (fs_mptail)
+ fs_mptail->next = m;
+
+ fs_mptail = m;
+ return 0;
+
+failure:
+ free(srcdup);
+ free(tgtdup);
+ free(m);
+ return -1;
+}
diff --git a/src/fs/src/mp_from_path.c b/src/fs/src/mp_from_path.c
new file mode 100644
index 0000000..4a963d3
--- /dev/null
+++ b/src/fs/src/mp_from_path.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <string.h>
+
+int fs_mp_from_path(const char *const path, struct fs_mp *const mp)
+{
+ for (const struct fs_mountpoint *p = fs_mphead; p; p = p->next)
+ if (!strcmp(path, p->tgt))
+ {
+ *mp = (const struct fs_mp)
+ {
+ .fs = p->fs,
+ .prv = p->prv,
+ .src = p->src,
+ .tgt= p->tgt
+ };
+
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/src/fs/src/mps_from_path.c b/src/fs/src/mps_from_path.c
new file mode 100644
index 0000000..4825ccc
--- /dev/null
+++ b/src/fs/src/mps_from_path.c
@@ -0,0 +1,89 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct fs_mp *find(const char *const path, size_t *const out)
+{
+ struct fs_mp *ret = NULL;
+ size_t n = 0;
+
+ for (const struct fs_mountpoint *p = fs_mphead; p; p = p->next)
+ {
+ const size_t len = strlen(p->tgt);
+
+ if (!strncmp(p->tgt, path, len))
+ {
+ const size_t sz = n + 1;
+ struct fs_mp *const m = realloc(ret, sz * sizeof *m);
+
+ if (!m)
+ goto failure;
+
+ m[n++] = (const struct fs_mp)
+ {
+ .fs = p->fs,
+ .prv = p->prv,
+ .src = p->src,
+ .tgt = p->tgt
+ };
+
+ ret = m;
+ }
+ }
+
+ *out = n;
+ return ret;
+
+failure:
+ free(ret);
+ return NULL;
+}
+
+static void sort(struct fs_mp *const m, const size_t n)
+{
+ for (size_t i = 1; i < n; i++)
+ {
+ struct fs_mp am = m[i];
+ const size_t len = strlen(am.tgt);
+ size_t j = i;
+
+ while (j && len < strlen(m[j - 1].tgt))
+ {
+ m[j] = m [j - 1];
+ j--;
+ }
+
+ m[j] = am;
+ }
+}
+
+struct fs_mp *fs_mps_from_path(const char *const path, size_t *const n)
+{
+ struct fs_mp *const ret = find(path, n);
+
+ if (!ret)
+ return NULL;
+
+ sort(ret, *n);
+ return ret;
+}
diff --git a/src/fs/src/next.c b/src/fs/src/next.c
new file mode 100644
index 0000000..62fdd80
--- /dev/null
+++ b/src/fs/src/next.c
@@ -0,0 +1,62 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+int fs_next(const char *const path, char **const out, size_t *const i)
+{
+ char *next = NULL;
+
+ if (*i >= strlen(path))
+ {
+ *out = NULL;
+ return 0;
+ }
+
+ const char *const s = &path[*i];
+
+ if (*s == '/')
+ {
+ if (!(next = strdup("/")))
+ goto failure;
+
+ (*i)++;
+ *out = next;
+ return 0;
+ }
+
+ const char *sep = strchr(s, '/');
+ next = sep ? strndup(s, sep - s) : strdup(s);
+
+ if (!next)
+ goto failure;
+ else if (sep)
+ while (*sep && *sep == '/')
+ sep++;
+
+ *i += sep ? sep - s : strlen(s);
+ *out = next;
+ return 0;
+
+failure:
+ free(next);
+ return -1;
+}
diff --git a/src/fs/src/parent.c b/src/fs/src/parent.c
new file mode 100644
index 0000000..9cf51f6
--- /dev/null
+++ b/src/fs/src/parent.c
@@ -0,0 +1,33 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *fs_parent(const char *const path)
+{
+ char *ret = NULL;
+ const char *const sep = strrchr(path, '/');
+
+ if (!sep || !(ret = strndup(path, sep - path + 1)))
+ return NULL;
+
+ return ret;
+}
diff --git a/src/fs/src/register.c b/src/fs/src/register.c
new file mode 100644
index 0000000..d28e47a
--- /dev/null
+++ b/src/fs/src/register.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <stdlib.h>
+
+int fs_register(const struct fs *const fs)
+{
+ struct fs_register *const r = malloc(sizeof *r);
+
+ if (!r)
+ return -1;
+ else if (!fs_rhead)
+ fs_rhead = r;
+ else if (fs_rtail)
+ fs_rtail->next = r;
+
+ fs_rtail = r;
+ *r = (const struct fs_register){.fs = fs};
+ return 0;
+}
diff --git a/src/fs/src/relpath.c b/src/fs/src/relpath.c
new file mode 100644
index 0000000..565ea53
--- /dev/null
+++ b/src/fs/src/relpath.c
@@ -0,0 +1,43 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <string.h>
+
+const char *fs_relpath(const char *const path)
+{
+ size_t lastn = 0;
+ const struct fs_mountpoint *mp = NULL;
+
+ for (const struct fs_mountpoint *m = fs_mphead; m; m = m->next)
+ {
+ const size_t n = strlen(m->tgt);
+
+ if (!strncmp(m->tgt, path, n) && lastn < n)
+ {
+ lastn = n;
+ mp = m;
+ }
+ }
+
+ if (!mp)
+ return NULL;
+
+ return path + strlen(mp->tgt);
+}
diff --git a/src/fs/src/update.c b/src/fs/src/update.c
new file mode 100644
index 0000000..1e6d9ea
--- /dev/null
+++ b/src/fs/src/update.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <fs/fs.h>
+#include <fs/types.h>
+#include <stddef.h>
+
+int fs_update(void)
+{
+ for (const struct fs_mountpoint *m = fs_mphead; m; m = m->next)
+ if (m->update && m->update(m->prv))
+ return -1;
+
+ return 0;
+}
diff --git a/src/gfx/CMakeLists.txt b/src/gfx/CMakeLists.txt
new file mode 100644
index 0000000..85bf890
--- /dev/null
+++ b/src/gfx/CMakeLists.txt
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(gfx)
+add_subdirectory(src)
+target_include_directories(gfx PUBLIC include)
+
+if(PS1_BUILD)
+ add_subdirectory(ps1)
+elseif(SDL1_2_BUILD)
+ add_subdirectory(sdl-1.2)
+endif()
diff --git a/src/gfx/include/gfx/gfx.h b/src/gfx/include/gfx/gfx.h
new file mode 100644
index 0000000..c9b4931
--- /dev/null
+++ b/src/gfx/include/gfx/gfx.h
@@ -0,0 +1,47 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GFX_H
+#define GFX_H
+
+#include <gfx/port.h>
+#include <stdbool.h>
+
+int gfx_init(void);
+int gfx_draw(void);
+int gfx_update(void);
+bool gfx_ready(void);
+int gfx_toggle_fullscreen(void);
+int gfx_set_fullscreen(short w, short h);
+bool gfx_fullscreen_available(void);
+bool gfx_fullscreen(void);
+int gfx_display_size(short *w, short *h);
+
+void gfx_rect_init(struct gfx_rect *r);
+void semitrans_rect_init(struct gfx_rect *r);
+void stp_4line_init(struct stp_4line *l);
+void quad_sort(struct quad *q);
+int gfx_rect_sort(struct gfx_rect *r);
+void stp_4line_sort(struct stp_4line *l);
+int quad_from_sprite(const struct gfx_sprite *s, struct quad *q);
+bool gfx_inside_drawenv(short x, short y, short w, short h);
+void gfx_deinit(void);
+
+extern int screen_w, screen_h;
+
+#endif /* GFX_H */
diff --git a/src/gfx/include/gfx/sprite.h b/src/gfx/include/gfx/sprite.h
new file mode 100644
index 0000000..7b1bf8d
--- /dev/null
+++ b/src/gfx/include/gfx/sprite.h
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GFX_SPRITE_H
+#define GFX_SPRITE_H
+
+#include <gfx/port.h>
+#include <stddef.h>
+
+typedef int (*gfx_read)(void *buf, size_t n, void *args);
+
+int gfx_sprite_load(struct gfx_sprite *s, gfx_read r, void *args);
+int gfx_sprite_sort(struct gfx_sprite *s);
+int gfx_sprite_clone(const struct gfx_sprite *src, struct gfx_sprite *dst);
+void gfx_sprite_free(struct gfx_sprite *s);
+
+#endif
diff --git a/src/gfx/ps1/CMakeLists.txt b/src/gfx/ps1/CMakeLists.txt
new file mode 100644
index 0000000..f98ee50
--- /dev/null
+++ b/src/gfx/ps1/CMakeLists.txt
@@ -0,0 +1,40 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(src)
+target_include_directories(gfx PUBLIC include PRIVATE private_include)
+target_link_libraries(gfx PRIVATE
+ drv_ps1_event
+ drv_ps1_dma
+ drv_ps1_irq
+ drv_ps1_gpu
+)
+
+set(modes VMODE_PAL VMODE_NTSC)
+
+if(VIDEO_MODE)
+ if(NOT "${VIDEO_MODE}" IN_LIST modes)
+ message(FATAL_ERROR "Invalid video mode ${VIDEO_MODE}. Available options:\n"
+ "${modes}\n"
+ "Run CMake again using one of the available video modes e.g.: cmake .. -DVIDEO_MODE=VMODE_PAL")
+ endif()
+
+ target_compile_definitions(gfx PRIVATE VIDEO_MODE=${VIDEO_MODE})
+else()
+ message(FATAL_ERROR "Please define video mode. Available options:\n"
+ "${modes}\n"
+ "Run CMake again using one of the available video modes e.g.: cmake .. -DVIDEO_MODE=VMODE_PAL")
+endif()
diff --git a/src/gfx/ps1/include/gfx/port.h b/src/gfx/ps1/include/gfx/port.h
new file mode 100644
index 0000000..faf9a50
--- /dev/null
+++ b/src/gfx/ps1/include/gfx/port.h
@@ -0,0 +1,126 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GFX_PS1_H
+#define GFX_PS1_H
+
+#include <stdint.h>
+
+union gfx_common
+{
+ struct
+ {
+ uint32_t tpagex :4, tpagey :1, stp :2, bpp :2, dither :1,
+ draw_to_disp :1, disable :1, xflip :1, yflip :1, :10;
+ uint8_t cmd;
+ } f;
+
+ uint32_t mask;
+};
+
+union gfx_sznext
+{
+ struct
+ {
+ uint32_t next :24, sz :8;
+ } f;
+
+ uint32_t cmd_next;
+};
+
+struct gfx_sprite
+{
+ union gfx_sznext sznext;
+ union gfx_common common;
+ uint8_t r, g, b;
+ uint8_t cmd;
+ int16_t x, y;
+ uint8_t u, v;
+ uint16_t clutid;
+ uint16_t w, h;
+};
+
+struct quad
+{
+ union gfx_sznext sznext;
+ uint8_t r, g, b;
+ uint8_t cmd;
+ int16_t x0, y0;
+ uint8_t u0, v0;
+ uint16_t clutid;
+ int16_t x1, y1;
+ uint8_t u1, v1;
+
+ union
+ {
+ struct
+ {
+ /* 0-8 Same as GP0(E1h).Bit0-8. */
+ uint16_t lb :9;
+ uint16_t :2;
+ /* 11 Same as GP0(E1h).Bit11. */
+ uint16_t hb :1;
+ uint16_t :4;
+ } bit;
+
+ uint16_t mask;
+ } tpage;
+
+ int16_t x2, y2;
+ uint8_t u2, v2;
+ uint16_t :16;
+ int16_t x3, y3;
+ uint8_t u3, v3;
+ uint16_t :16;
+};
+
+struct gfx_rect
+{
+ union gfx_sznext sznext;
+ union gfx_common common;
+ uint8_t r, g, b;
+ uint8_t cmd;
+ int16_t x, y;
+ uint16_t w, h;
+};
+
+struct stp_4line
+{
+ union gfx_sznext sznext;
+ union gfx_common common;
+ uint8_t r, g, b;
+ uint8_t cmd;
+ int16_t x, y;
+
+ struct stp_4line_vtx
+ {
+ uint32_t r :8, g :8, b :8, :8;
+ int16_t x, y;
+ } vertices[4];
+
+ uint32_t end;
+};
+
+void gfx_add_to_list(union gfx_sznext *p);
+void *gfx_heap_top(void);
+struct gfx_sprite *gfx_sprite_get(void);
+struct quad *quad_get(void);
+struct gfx_rect *gfx_rect_get(void);
+struct stp_4line *stp_4line_get(void);
+
+#endif
diff --git a/src/gfx/ps1/private_include/gfx/private.h b/src/gfx/ps1/private_include/gfx/private.h
new file mode 100644
index 0000000..72d8f39
--- /dev/null
+++ b/src/gfx/ps1/private_include/gfx/private.h
@@ -0,0 +1,19 @@
+#ifndef GFX_PS1_PRIVATE_H
+#define GFX_PS1_PRIVATE_H
+
+#include <gfx/gfx.h>
+
+enum
+{
+ SCREEN_W = 640,
+ SCREEN_H = 480
+};
+
+void gfx_swapheap(void);
+void gfx_initenvs(void);
+void gfx_swapbuffers(void);
+void gfx_swapenvs(void);
+
+extern int gfx_vblank_ev;
+
+#endif
diff --git a/src/gfx/ps1/src/4line.c b/src/gfx/ps1/src/4line.c
new file mode 100644
index 0000000..766eb2d
--- /dev/null
+++ b/src/gfx/ps1/src/4line.c
@@ -0,0 +1,15 @@
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <psxgpu.h>
+#include <stdint.h>
+#include <string.h>
+
+void stp_4line_init(struct stp_4line *const l)
+{
+ memset(l, 0, sizeof *l);
+ l->sznext.f.sz = (sizeof *l - sizeof l->sznext) / sizeof (uint32_t);
+ l->common.f.cmd = DRAW_MODE;
+ l->cmd = 0x5A;
+ enum {TERMINATION_CODE = 0x55555555};
+ l->end = TERMINATION_CODE;
+}
diff --git a/src/gfx/ps1/src/CMakeLists.txt b/src/gfx/ps1/src/CMakeLists.txt
new file mode 100644
index 0000000..5b08b24
--- /dev/null
+++ b/src/gfx/ps1/src/CMakeLists.txt
@@ -0,0 +1,33 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(gfx PRIVATE
+ # 4line.c
+ # env.c
+ draw.c
+ heap.c
+ init.c
+ ready.c
+ swapenvs.c
+ # quad.c
+ # rect.c
+ # sort.c
+ # sprite.c
+ vblank.c
+)
+
+add_subdirectory(sprite)
+add_subdirectory(rect)
diff --git a/src/gfx/ps1/src/deinit.c b/src/gfx/ps1/src/deinit.c
new file mode 100644
index 0000000..e5683f0
--- /dev/null
+++ b/src/gfx/ps1/src/deinit.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+
+void gfx_deinit(void)
+{
+}
diff --git a/src/gfx/ps1/src/draw.c b/src/gfx/ps1/src/draw.c
new file mode 100644
index 0000000..a935143
--- /dev/null
+++ b/src/gfx/ps1/src/draw.c
@@ -0,0 +1,71 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <drv/ps1/dma.h>
+#include <drv/ps1/gpu.h>
+#include <stddef.h>
+
+static union gfx_sznext *first, *last;
+
+void gfx_add_to_list(union gfx_sznext *const p)
+{
+ if (!first)
+ first = p;
+ else if (last)
+ last->f.next = (uint32_t)p;
+
+ last = p;
+}
+
+int gfx_draw(void)
+{
+ static union gfx_sznext term = {.cmd_next = 0xffffff};
+
+ gfx_add_to_list(&term);
+
+ if (SCREEN_W != 640)
+ gfx_swapenvs();
+
+ gfx_swapheap();
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .dma =
+ {
+ .cmd = GP1_DMA_DIR,
+ .dir = GP1_DMA_DIR_CPU_TO_GP0
+ }
+ }.mask;
+
+ D2_MADR->mask = (uint32_t)first;
+ D2_BCR->syncmode_2.reserved = 0;
+ D2_CHCR->mask = (const union chcr)
+ {
+ .bits =
+ {
+ .sync_mode = CHCR_SYNC_MODE_LINKED_LIST,
+ .dir = CHCR_DIR_FROM_RAM,
+ .start_busy = 1
+ }
+ }.mask;
+
+ first = NULL;
+ return 0;
+}
diff --git a/src/gfx/ps1/src/env.c b/src/gfx/ps1/src/env.c
new file mode 100644
index 0000000..100f366
--- /dev/null
+++ b/src/gfx/ps1/src/env.c
@@ -0,0 +1,71 @@
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <psxgpu.h>
+#include <errno.h>
+#include <stdbool.h>
+
+static GsDispEnv dispenv;
+enum {ENV_Y = SCREEN_H + 16};
+
+static GsDrawEnv drawenv =
+{
+ .y = ENV_Y,
+ .w = SCREEN_W,
+ .h = SCREEN_H
+};
+
+int screen_w = SCREEN_W, screen_h = SCREEN_H;
+
+void gfx_swapbuffers(void)
+{
+ const short y = drawenv.y;
+
+ drawenv.y = dispenv.y;
+ dispenv.y = y;
+ GsSetDrawEnv(&drawenv);
+ GsSetDispEnv(&dispenv);
+}
+
+void gfx_initenvs(void)
+{
+ GsSetDrawEnv(&drawenv);
+ GsSetDispEnv(&dispenv);
+}
+
+int gfx_toggle_fullscreen(void)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+int gfx_set_fullscreen(const short w, const short h)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+bool gfx_fullscreen_available(void)
+{
+ return false;
+}
+
+bool gfx_fullscreen(void)
+{
+ return true;
+}
+
+int gfx_display_size(short *const w, short *const h)
+{
+ *w = SCREEN_W;
+ *h = SCREEN_H;
+ return 0;
+}
+
+bool gfx_inside_drawenv(const short x, const short y, const short w,
+ const short h)
+{
+ return (x + w >= 0)
+ && x < drawenv.w
+ && (y + h >= 0)
+ && y < drawenv.h;
+}
diff --git a/src/gfx/ps1/src/heap.c b/src/gfx/ps1/src/heap.c
new file mode 100644
index 0000000..402ee41
--- /dev/null
+++ b/src/gfx/ps1/src/heap.c
@@ -0,0 +1,74 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <stddef.h>
+
+static unsigned int sel;
+static size_t heap_i;
+
+void gfx_swapheap(void)
+{
+ sel ^= 1;
+ heap_i = 0;
+}
+
+static void *get_element(const size_t sz)
+{
+ enum
+ {
+ HEAP_SZ = sizeof (struct gfx_rect)
+ + (SCREEN_W / 10) * sizeof (struct gfx_sprite),
+ N_HEAPS = 2
+ };
+
+ static char heaps[N_HEAPS][HEAP_SZ];
+ const size_t new_sz = heap_i + sz;
+ void *ret = NULL;
+
+ if (new_sz <= sizeof *heaps / sizeof **heaps)
+ {
+ ret = &heaps[sel][heap_i];
+ heap_i = new_sz;
+ }
+ else
+ return NULL;
+
+ return ret;
+}
+
+struct gfx_sprite *gfx_sprite_get(void)
+{
+ return get_element(sizeof (struct gfx_sprite));
+}
+
+struct quad *quad_get(void)
+{
+ return get_element(sizeof (struct quad));
+}
+
+struct gfx_rect *gfx_rect_get(void)
+{
+ return get_element(sizeof (struct gfx_rect));
+}
+
+struct stp_4line *stp_4line_get(void)
+{
+ return get_element(sizeof (struct stp_4line));
+}
diff --git a/src/gfx/ps1/src/init.c b/src/gfx/ps1/src/init.c
new file mode 100644
index 0000000..a640202
--- /dev/null
+++ b/src/gfx/ps1/src/init.c
@@ -0,0 +1,199 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/dma.h>
+#include <drv/ps1/gpu.h>
+#include <drv/ps1/irq.h>
+#include <stddef.h>
+
+struct res
+{
+ int hres, hres2, vres, interlace;
+};
+
+static void getres(const short w, struct res *const r)
+{
+ *r = (const struct res){0};
+
+ switch (w)
+ {
+ case 320:
+ r->hres = 1;
+ break;
+ case 368:
+ r->hres2 = 1;
+ break;
+ case 512:
+ r->hres = 2;
+ break;
+ case 640:
+ r->hres = 3;
+ r->vres = 1;
+ r->interlace = 1;
+ break;
+ }
+}
+
+volatile int vblank_set;
+
+static int irq(void)
+{
+ vblank_set = 1;
+ I_STAT->bits.vblank = 0;
+ return 0;
+}
+
+int gfx_init(void)
+{
+ const int event = OpenEvent(CLASS_VBLANK, SPEC_INTERRUPTED, MODE_EXECUTE,
+ irq);
+
+ if (event == -1)
+ return -1;
+
+ I_MASK->bits.vblank = 1;
+ EnableEvent(gfx_vblank_ev = event);
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {.reset_gpu.cmd = GP1_RESET_GPU}.mask;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {
+ .fill_vram =
+ {
+ .cmd = GP0_FILL_VRAM,
+ .w = 1024 / 16,
+ .h = 512
+ }
+ }.mask;
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {.reset_cmdbuf.cmd = GP1_RESET_CMDBUF}.mask;
+
+ DPCR->mask |= (const union dpcr){.bits.gpu_en = 1}.mask;
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .dma =
+ {
+ .cmd = GP1_DMA_DIR,
+ .dir = GP1_DMA_DIR_CPU_TO_GP0
+ }
+ }.mask;
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .display =
+ {
+ .cmd = GP1_DISPLAY_ENABLE,
+ }
+ }.mask;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {
+ .draw_mode =
+ {
+ .cmd = GP0_DRAW_MODE,
+ .draw_to_display = 1
+ }
+ }.mask;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {.tex_window.cmd = GP0_TEX_WINDOW}.mask;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {.draw_area_tl.cmd = GP0_DRAW_AREA_TOP_LEFT}.mask;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {
+ .draw_area_br =
+ {
+ .cmd = GP0_DRAW_AREA_BOTTOM_RIGHT,
+ .x = SCREEN_W - 1,
+ .y = SCREEN_H - 1,
+ }
+ }.mask;
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .h_display_range =
+ {
+ .cmd = GP1_H_DISPLAY_RANGE,
+ .x1 = 0x260,
+ .x2 = 0x260 + 320 * 8
+ }
+ }.mask;
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .disparea =
+ {
+ .cmd = GP1_START_DISPLAY_AREA
+ }
+ }.mask;
+
+#if 0
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .v_display_range =
+ {
+ .cmd = GP1_V_DISPLAY_RANGE,
+#if VIDEO_MODE == VMODE_PAL
+ .y1 = 0xa3,
+ .y2 = 0xa3 + (SCREEN_H / 2)
+#elif VIDEO_MODE == VMODE_NTSC
+ .y1 = 0x88 - (224 / 2),
+ .y2 = 0x88 + (224 / 2)
+#endif
+ }
+ }.mask;
+#else
+#if 0
+ /* TODO: use structs above. */
+ GP1->mask = 0x06C4E24E;
+ GP1->mask = 0x07040010;
+#else
+ /* values found from BIOS init state*/
+ GP1->mask = 0x06c7e27e;
+ GP1->mask = 0x0704682b;
+#endif
+#endif
+
+ struct res r;
+
+ getres(SCREEN_W, &r);
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .display_mode =
+ {
+ .cmd = GP1_DISPLAY_MODE,
+ .hres = r.hres,
+ .hres2 = r.hres2,
+ .vres = r.vres,
+ .vinterlace = r.interlace,
+#if VIDEO_MODE == VMODE_PAL
+ .vmode = 1
+#endif
+ }
+ }.mask;
+
+ return 0;
+}
diff --git a/src/gfx/ps1/src/quad.c b/src/gfx/ps1/src/quad.c
new file mode 100644
index 0000000..bfabee2
--- /dev/null
+++ b/src/gfx/ps1/src/quad.c
@@ -0,0 +1,24 @@
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <gfx/port.h>
+#include <stdint.h>
+#include <string.h>
+
+static void quad_init(struct quad *const q)
+{
+ memset(q, 0, sizeof *q);
+ q->sznext.f.sz = (sizeof *q - sizeof q->sznext) / sizeof (uint32_t);
+ q->cmd = 0x2d;
+}
+
+int quad_from_sprite(const struct gfx_sprite *const s, struct quad *const q)
+{
+ quad_init(q);
+ q->tpage.mask = s->common.mask;
+ q->clutid = s->clutid;
+ q->u0 = q->u2 = s->u;
+ q->v0 = q->v1 = s->v;
+ q->u1 = q->u3 = s->u + s->w - 1;
+ q->v2 = q->v3 = s->v + s->h - 1;
+ return 0;
+}
diff --git a/src/gfx/ps1/src/ready.c b/src/gfx/ps1/src/ready.c
new file mode 100644
index 0000000..bcb5b29
--- /dev/null
+++ b/src/gfx/ps1/src/ready.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <drv/ps1/event.h>
+#include <drv/ps1/gpu.h>
+#include <stdbool.h>
+
+bool gfx_ready(void)
+{
+ extern volatile int vblank_set;
+
+ if (GPUSTAT->bits.ready_cmd
+ && GPUSTAT->bits.ready_dma
+ && vblank_set)
+ {
+ vblank_set = 0;
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/gfx/ps1/src/rect/CMakeLists.txt b/src/gfx/ps1/src/rect/CMakeLists.txt
new file mode 100644
index 0000000..a14378e
--- /dev/null
+++ b/src/gfx/ps1/src/rect/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(gfx PRIVATE
+ init.c
+ sort.c
+)
diff --git a/src/gfx/ps1/src/rect/init.c b/src/gfx/ps1/src/rect/init.c
new file mode 100644
index 0000000..5fe0a85
--- /dev/null
+++ b/src/gfx/ps1/src/rect/init.c
@@ -0,0 +1,41 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <drv/ps1/gpu.h>
+
+static void common_init(struct gfx_rect *const r)
+{
+ *r = (const struct gfx_rect){0};
+ r->sznext.f.sz = (sizeof *r - sizeof r->sznext) / sizeof (uint32_t);
+ r->common.f.cmd = GP0_DRAW_MODE;
+ r->common.f.draw_to_disp = 1;
+}
+
+void gfx_rect_init(struct gfx_rect *const r)
+{
+ common_init(r);
+ r->cmd = 0x60;
+}
+
+void gfx_semitrans_rect_init(struct gfx_rect *const r)
+{
+ common_init(r);
+ r->cmd = 0x62;
+}
diff --git a/src/gfx/ps1/src/rect/sort.c b/src/gfx/ps1/src/rect/sort.c
new file mode 100644
index 0000000..b7f5ebc
--- /dev/null
+++ b/src/gfx/ps1/src/rect/sort.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <drv/ps1/gpu.h>
+
+int gfx_rect_sort(struct gfx_rect *const r)
+{
+ gfx_add_to_list(&r->sznext);
+ return 0;
+}
diff --git a/src/gfx/ps1/src/sprite/CMakeLists.txt b/src/gfx/ps1/src/sprite/CMakeLists.txt
new file mode 100644
index 0000000..32e1b9f
--- /dev/null
+++ b/src/gfx/ps1/src/sprite/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(gfx PRIVATE
+ clone.c
+ free.c
+ load.c
+ sort.c
+)
diff --git a/src/gfx/ps1/src/sprite/clone.c b/src/gfx/ps1/src/sprite/clone.c
new file mode 100644
index 0000000..45bc802
--- /dev/null
+++ b/src/gfx/ps1/src/sprite/clone.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+
+int gfx_sprite_clone(const struct gfx_sprite *const src,
+ struct gfx_sprite *const dst)
+{
+ *dst = *src;
+ return 0;
+}
diff --git a/src/gfx/ps1/src/sprite/free.c b/src/gfx/ps1/src/sprite/free.c
new file mode 100644
index 0000000..922c1ff
--- /dev/null
+++ b/src/gfx/ps1/src/sprite/free.c
@@ -0,0 +1,23 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+
+void sprite_free(struct gfx_sprite *const src)
+{
+}
diff --git a/src/gfx/ps1/src/sprite/load.c b/src/gfx/ps1/src/sprite/load.c
new file mode 100644
index 0000000..2dd12ae
--- /dev/null
+++ b/src/gfx/ps1/src/sprite/load.c
@@ -0,0 +1,192 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/sprite.h>
+#include <gfx/private.h>
+#include <drv/ps1/gpu.h>
+#include <stdint.h>
+
+static void init(struct gfx_sprite *const s)
+{
+ *s = (const struct gfx_sprite){0};
+ s->sznext.f.sz = (sizeof *s - sizeof s->sznext) / sizeof (uint32_t);
+ s->common.f.cmd = GP0_DRAW_MODE;
+ s->common.f.draw_to_disp = 1;
+ s->cmd = GP0_TEXTRECT_VARSZ_OPAQ_RAW;
+}
+
+struct tim_pos
+{
+ uint16_t x, y, w, h;
+};
+
+static void transfer_init(const struct tim_pos *const p)
+{
+ while (!GPUSTAT->bits.ready_cmd)
+ ;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {.copy_rect.cmd = GP0_COPY_RECT_CPU_VRAM}.mask;
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {.coord = {.x = p->x, .y = p->y}}.mask;
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {.size = {.w = p->w, .h = p->h}}.mask;
+}
+
+static int transfer(const size_t sz, const gfx_read r, void *const args)
+{
+ const size_t rem = sz % sizeof (uint32_t);
+
+ if (sz >= sizeof (uint32_t))
+ {
+ for (size_t i = 0; i < sz / sizeof (uint32_t); i++)
+ {
+ uint32_t pix;
+
+ if (r(&pix, sizeof pix, args))
+ return -1;
+
+ GP0->mask = pix;
+ }
+ }
+
+ if (rem)
+ {
+ uint32_t pix = 0;
+
+ if (r(&pix, rem, args))
+ return -1;
+
+ GP0->mask = pix;
+ }
+
+ return 0;
+}
+
+struct header
+{
+ uint32_t sz;
+ struct tim_pos pos;
+};
+
+static short get_clutid(const short x, const short y)
+{
+ return (x & 0x3ff) >> 4 | (y & 0x1ff) << 6;
+}
+
+static int upload_clut(struct gfx_sprite *const s, const gfx_read r,
+ void *const args)
+{
+ struct header clut;
+
+ if (r(&clut, sizeof clut, args))
+ return -1;
+
+ transfer_init(&clut.pos);
+
+ const size_t sz = clut.sz - sizeof clut;
+
+ if (transfer(sz, r, args))
+ return -1;
+
+ s->clutid = get_clutid(clut.pos.x, clut.pos.y);
+ return 0;
+}
+
+enum bpp
+{
+ BPP_4 = 0,
+ BPP_8 = 1,
+ BPP_16 = 2,
+ BPP_24 = 4
+};
+
+static int upload_img(struct gfx_sprite *const s, const enum bpp bpp,
+ const gfx_read r, void *const args)
+{
+ struct header img;
+
+ if (r(&img, sizeof img, args))
+ return -1;
+
+ transfer_init(&img.pos);
+
+ const size_t sz = img.sz - sizeof img;
+
+ if (transfer(sz, r, args))
+ return -1;
+
+ enum
+ {
+ VRAM_X = 1024,
+ VRAM_Y = 512,
+ TPAGE_WIDTH = 64
+ };
+
+ s->common.f.tpagex = img.pos.x / TPAGE_WIDTH;
+ s->common.f.tpagey = img.pos.y / (VRAM_Y / 2);
+ s->u = img.pos.x % TPAGE_WIDTH;
+ s->v = img.pos.y % (VRAM_Y / 2);
+
+ switch (bpp)
+ {
+ case BPP_4:
+ s->w = img.pos.w * 4;
+ s->u <<= 2;
+ break;
+
+ case BPP_8:
+ s->w = img.pos.w * 2;
+ s->u <<= 1;
+ break;
+
+ case BPP_16:
+ s->w = img.pos.w;
+ break;
+
+ case BPP_24:
+ s->w = img.pos.w + (img.pos.w / 2);
+ break;
+ }
+
+ s->h = img.pos.h;
+ return 0;
+}
+
+int gfx_sprite_load(struct gfx_sprite *s, const gfx_read r, void *const args)
+{
+ init(s);
+
+ struct
+ {
+ uint32_t version, bpp :3, has_clut :1, :28;
+ } h;
+
+ enum {VERSION_ID = 0x10};
+
+ if (r(&h, sizeof h, args)
+ || h.version != VERSION_ID
+ || h.bpp == BPP_24
+ || (h.has_clut && upload_clut(s, r, args))
+ || upload_img(s, h.bpp, r, args))
+ return -1;
+
+ s->common.f.bpp = h.bpp ? __builtin_ctz(h.bpp) + 1 : 0;
+ return 0;
+}
diff --git a/src/gfx/ps1/src/sprite/sort.c b/src/gfx/ps1/src/sprite/sort.c
new file mode 100644
index 0000000..3a4b020
--- /dev/null
+++ b/src/gfx/ps1/src/sprite/sort.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+
+int gfx_sprite_sort(struct gfx_sprite *const s)
+{
+ gfx_add_to_list(&s->sznext);
+ return 0;
+}
diff --git a/src/gfx/ps1/src/swapenvs.c b/src/gfx/ps1/src/swapenvs.c
new file mode 100644
index 0000000..0b08ee2
--- /dev/null
+++ b/src/gfx/ps1/src/swapenvs.c
@@ -0,0 +1,58 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <drv/ps1/gpu.h>
+
+void gfx_swapenvs(void)
+{
+ static short dispenv, drawenv = 256;
+ const short y = dispenv;
+
+ dispenv = drawenv;
+ drawenv = y;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {
+ .draw_area_tl =
+ {
+ .cmd = GP0_DRAW_AREA_TOP_LEFT,
+ .y = drawenv
+ }
+ }.mask;
+
+ GP0->mask = (const union drv_ps1_gpu_gp0)
+ {
+ .draw_area_br =
+ {
+ .cmd = GP0_DRAW_AREA_BOTTOM_RIGHT,
+ .x = SCREEN_W - 1,
+ .y = drawenv + SCREEN_H - 1,
+ }
+ }.mask;
+
+ GP1->mask = (const union drv_ps1_gpu_gp1)
+ {
+ .disparea =
+ {
+ .cmd = GP1_START_DISPLAY_AREA,
+ .y = dispenv
+ }
+ }.mask;
+}
diff --git a/src/libc/src/free.c b/src/gfx/ps1/src/vblank.c
index d89a80a..eb47597 100644
--- a/src/libc/src/free.c
+++ b/src/gfx/ps1/src/vblank.c
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -16,8 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
+#include <gfx/private.h>
-void free(void *const ptr)
-{
-}
+int gfx_vblank_ev;
diff --git a/src/gfx/sdl-1.2/CMakeLists.txt b/src/gfx/sdl-1.2/CMakeLists.txt
new file mode 100644
index 0000000..cd37d06
--- /dev/null
+++ b/src/gfx/sdl-1.2/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(src)
+target_include_directories(gfx PUBLIC include PRIVATE private_include)
+target_link_libraries(gfx PUBLIC SDL::SDL PRIVATE SDL::SDL_gfx)
diff --git a/src/gfx/sdl-1.2/include/gfx/port.h b/src/gfx/sdl-1.2/include/gfx/port.h
new file mode 100644
index 0000000..bf94a38
--- /dev/null
+++ b/src/gfx/sdl-1.2/include/gfx/port.h
@@ -0,0 +1,58 @@
+#ifndef GFX_SDL_H
+#define GFX_SDL_H
+
+#include <SDL.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct gfx_sprite
+{
+ SDL_Surface *s, *s_x;
+ short x, y, w, h;
+ unsigned char u, v;
+ bool transparent;
+};
+
+struct quad
+{
+ unsigned char r, g, b;
+ short x0, x1, x2, x3;
+ short y0, y1, y2, y3;
+ unsigned char u0, u1, u2, u3;
+ unsigned char v0, v1, v2, v3;
+ short w, h;
+ bool transparent;
+ SDL_Surface *s, *s_x;
+};
+
+struct gfx_rect
+{
+ unsigned char r, g, b;
+ short x, y, w, h;
+ bool stp;
+};
+
+struct stp_4line
+{
+ short x, y;
+ unsigned char r, g, b;
+
+ struct stp_4line_vtx
+ {
+ unsigned char r, g, b;
+ short x, y;
+ } vertices[4];
+};
+
+#define common_get_or_ret(t, x, ret) \
+ struct t x##__, *const x = &x##__
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_SDL_H */
diff --git a/src/gfx/sdl-1.2/private_include/gfx/private.h b/src/gfx/sdl-1.2/private_include/gfx/private.h
new file mode 100644
index 0000000..e1af764
--- /dev/null
+++ b/src/gfx/sdl-1.2/private_include/gfx/private.h
@@ -0,0 +1,26 @@
+#ifndef GFX_SDL_12_PRIVATE_H
+#define GFX_SDL_12_PRIVATE_H
+
+#include <gfx/gfx.h>
+#include <SDL.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+enum
+{
+ SCREEN_W = 320,
+ SCREEN_H = 240
+};
+
+int sprite_screen_resize_ev(struct gfx_sprite *s);
+void gfx_register_sprite(struct gfx_sprite *s);
+SDL_Surface *gfx_screen(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_SDL_12_PRIVATE_H */
diff --git a/src/gfx/sdl-1.2/src/CMakeLists.txt b/src/gfx/sdl-1.2/src/CMakeLists.txt
new file mode 100644
index 0000000..75ccb78
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(gfx PRIVATE
+ env.c
+ line.c
+ quad.c
+ rect.c
+ sprite.c
+)
diff --git a/src/gfx/sdl-1.2/src/env.c b/src/gfx/sdl-1.2/src/env.c
new file mode 100644
index 0000000..2a51b97
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/env.c
@@ -0,0 +1,204 @@
+#include <gfx/gfx.h>
+#include <gfx/private.h>
+#include <sdl-1.2/gfx/private.h>
+#include <SDL.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int screen_w = SCREEN_W, screen_h = SCREEN_H;
+static bool fullscreen;
+static SDL_Surface *screen;
+static struct gfx_sprite **list;
+static size_t list_len;
+
+void gfx_deinit(void)
+{
+ /* screen should be already freed by SDL_Quit. */
+ free(list);
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
+static struct
+{
+ int w, h;
+} display, windowed;
+
+void gfx_register_sprite(struct gfx_sprite *const s)
+{
+ list = realloc(list, (list_len + 1) * sizeof *list);
+
+ if (list)
+ list[list_len++] = s;
+}
+
+static int resize_screen(int w, int h, const bool full_screen)
+{
+ Uint32 flags = SDL_HWSURFACE | SDL_RESIZABLE | SDL_ANYFORMAT | SDL_DOUBLEBUF;
+
+ const SDL_VideoInfo *const info = SDL_GetVideoInfo();
+
+ if (!info)
+ {
+ fprintf(stderr, "SDL_GetVideoInfo: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ static bool init;
+
+ if (!init)
+ {
+ display.w = info->current_w;
+ display.h = info->current_h;
+ init = true;
+ }
+
+ if (fullscreen)
+ {
+ flags |= SDL_FULLSCREEN;
+ w = display.w;
+ h = display.h;
+ }
+ else
+ {
+ windowed.w = w;
+ windowed.h = h;
+ }
+
+ int bpp = info->vfmt->BitsPerPixel;
+
+ if (screen)
+ SDL_FreeSurface(screen);
+
+ const int max_bpp = SDL_VideoModeOK(w, h, 0, flags);
+
+ if (max_bpp < 0)
+ {
+ fprintf(stderr, "SDL_VideoModeOK: %s\n", SDL_GetError());
+ return -1;
+ }
+ else if (bpp > max_bpp)
+ bpp = max_bpp;
+
+ if (!(screen = SDL_SetVideoMode(w, h, 0, flags)))
+ {
+ fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ for (size_t i = 0; i < list_len; i++)
+ if (sprite_screen_resize_ev(list[i]))
+ return -1;
+
+ screen_w = w;
+ screen_h = h;
+ fullscreen = full_screen;
+ return 0;
+}
+
+SDL_Surface *gfx_screen(void)
+{
+ return screen;
+}
+
+int gfx_display_size(short *const w, short *const h)
+{
+ *w = display.w;
+ *h = display.h;
+ return 0;
+}
+
+int gfx_init(void)
+{
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO))
+ {
+ fprintf(stderr, "%s: SDL_InitSubSystem: %s\n",
+ __func__, SDL_GetError());
+ return -1;
+ }
+
+ return resize_screen(screen_w, screen_h, fullscreen);
+}
+
+bool gfx_inside_drawenv(const short x, const short y, const short w,
+ const short h)
+{
+ return (x + w >= 0)
+ && x < screen_w
+ && (y + h >= 0)
+ && y < screen_h;
+}
+
+static int get_resize_events(void)
+{
+ int n;
+ SDL_Event ev;
+
+ while ((n = SDL_PeepEvents(&ev, 1, SDL_GETEVENT,
+ SDL_VIDEORESIZEMASK)) > 0)
+ {
+ if (ev.type == SDL_VIDEORESIZE)
+ {
+ const SDL_ResizeEvent *const res = &ev.resize;
+
+ if (resize_screen(res->w, res->h, false))
+ return -1;
+ }
+ }
+
+ if (n < 0)
+ {
+ fprintf(stderr, "%s: SDL_PeepEvents: %s\n",
+ __func__, SDL_GetError());
+ return -1;
+ }
+
+ return 0;
+}
+
+int gfx_toggle_fullscreen(void)
+{
+ fullscreen ^= true;
+
+ const int w = fullscreen ? display.w : windowed.w;
+ const int h = fullscreen ? display.h : windowed.h;
+
+ return resize_screen(w, h, fullscreen);
+}
+
+int gfx_set_fullscreen(const short w, const short h)
+{
+ return resize_screen(display.w = w, display.h = h, fullscreen = true);
+}
+
+bool gfx_fullscreen_available(void)
+{
+ return true;
+}
+
+bool gfx_fullscreen(void)
+{
+ return fullscreen;
+}
+
+int gfx_draw(void)
+{
+ enum {FPS = 50, REFRESH_MS = 1000 / FPS};
+ static Uint32 prev;
+ const Uint32 cur = SDL_GetTicks();
+
+ if (cur - prev < REFRESH_MS)
+ SDL_Delay(REFRESH_MS - (cur - prev));
+
+ prev = SDL_GetTicks();
+
+ if (SDL_Flip(screen))
+ {
+ fprintf(stderr, "SDL_Flip: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ get_resize_events();
+ return 0;
+}
diff --git a/src/gfx/sdl-1.2/src/line.c b/src/gfx/sdl-1.2/src/line.c
new file mode 100644
index 0000000..b06a414
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/line.c
@@ -0,0 +1,16 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <sdl-1.2/gfx/private.h>
+#include <stddef.h>
+
+void stp_4line_init(struct stp_4line *const l)
+{
+}
+
+void semitrans_stp_4line_init(struct stp_4line *r)
+{
+}
+
+void stp_4line_sort(struct stp_4line *const r)
+{
+}
diff --git a/src/gfx/sdl-1.2/src/quad.c b/src/gfx/sdl-1.2/src/quad.c
new file mode 100644
index 0000000..1617a8b
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/quad.c
@@ -0,0 +1,44 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <sdl-1.2/gfx/private.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+int quad_from_sprite(const struct gfx_sprite *const s, struct quad *const q)
+{
+ q->s = s->s;
+ q->s_x = s->s_x;
+ q->u0 = q->u2 = s->u;
+ q->v0 = q->v1 = s->v;
+ q->u1 = q->u3 = s->u + s->w - 1;
+ q->v2 = q->v3 = s->v + s->h - 1;
+ q->w = s->w;
+ q->h = s->h;
+ return 0;
+}
+
+void quad_sort(struct quad *const q)
+{
+ const bool xflip = q->x0 > q->x1;
+
+ SDL_Rect r =
+ {
+ .x = xflip ? q->x1 : q->x0,
+ .y = q->y0
+ };
+
+ const short w = q->u1 - q->u0 + 1, h = q->v2 - q->v0 + 1;
+
+ SDL_Rect clip =
+ {
+ .x = xflip ? q->w - q->u0 - w: q->u0,
+ .y = q->v0,
+ .w = w,
+ .h = h
+ };
+
+ SDL_Surface *const s = xflip ? q->s_x : q->s;
+
+ if (SDL_BlitSurface(s, &clip, gfx_screen(), &r))
+ fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError());
+}
diff --git a/src/gfx/sdl-1.2/src/rect.c b/src/gfx/sdl-1.2/src/rect.c
new file mode 100644
index 0000000..57a2ab3
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/rect.c
@@ -0,0 +1,35 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <sdl-1.2/gfx/private.h>
+#include <SDL.h>
+
+void gfx_rect_sort(struct gfx_rect *const r)
+{
+ SDL_Rect rct =
+ {
+ .x = r->x,
+ .y = r->y,
+ .w = r->w,
+ .h = r->h
+ };
+
+ SDL_Surface *const screen = gfx_screen();
+ const Uint32 map = SDL_MapRGB(screen->format, r->r, r->g, r->b);
+
+ if (SDL_FillRect(screen, &rct, map))
+ {
+ fprintf(stderr, "SDL_FillRect: %s\n", SDL_GetError());
+ return;
+ }
+}
+
+void gfx_rect_init(struct gfx_rect *const r)
+{
+ *r = (const struct gfx_rect){0};
+}
+
+void semitrans_rect_init(struct gfx_rect *const r)
+{
+ gfx_rect_init(r);
+ r->stp = true;
+}
diff --git a/src/gfx/sdl-1.2/src/sprite.c b/src/gfx/sdl-1.2/src/sprite.c
new file mode 100644
index 0000000..086e2b5
--- /dev/null
+++ b/src/gfx/sdl-1.2/src/sprite.c
@@ -0,0 +1,143 @@
+#include <gfx/gfx.h>
+#include <gfx/port.h>
+#include <header.h>
+#include <sdl-1.2/gfx/private.h>
+#include <SDL.h>
+#include <SDL_rotozoom.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void sprite_free(struct gfx_sprite *const s)
+{
+ if (s && s->s)
+ SDL_FreeSurface(s->s);
+}
+
+int sprite_clone(const struct gfx_sprite *const src, struct gfx_sprite *const dst)
+{
+ *dst = *src;
+ return 0;
+}
+
+static int set_transparent(SDL_Surface *const s)
+{
+ /* Magenta as transparent. */
+ const Uint32 map = SDL_MapRGB(s->format, 255, 0, 255);
+ const int ret = SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, map);
+
+ if (ret)
+ fprintf(stderr, "SDL_SetColorKey: %s\n", SDL_GetError());
+
+ return ret;
+}
+
+int sprite_screen_resize_ev(struct gfx_sprite *const s)
+{
+ int ret = -1;
+ SDL_Surface *const old = s->s, *const old_x = s->s_x;
+
+ if (s->transparent && (set_transparent(old) || set_transparent(old_x)))
+ goto end;
+ else if (!(s->s = SDL_DisplayFormat(old)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(s->s_x = SDL_DisplayFormat(old_x)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ SDL_FreeSurface(old);
+ SDL_FreeSurface(old_x);
+ return ret;
+}
+
+static int load_header(struct gfx_sprite *const s, FILE *const f)
+{
+ if (header_load_bool(f, "transparent", &s->transparent))
+ return -1;
+
+ return 0;
+}
+
+static int load_bitmap(struct gfx_sprite *const s, FILE *const f)
+{
+ int ret = -1;
+ SDL_RWops *ops = NULL;
+ SDL_Surface *ts = NULL, *zs = NULL;
+
+ if (!(ops = SDL_RWFromFP(f, 0)))
+ {
+ fprintf(stderr, "SDL_RWFromFP: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(ts = SDL_LoadBMP_RW(ops, 0)))
+ {
+ fprintf(stderr, "SDL_LoadBMP_RW: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(zs = zoomSurface(ts, -1, 1, 0)))
+ {
+ fprintf(stderr, "zoomSurface: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (s->transparent && (set_transparent(ts) || set_transparent(zs)))
+ goto end;
+ else if (!(s->s = SDL_DisplayFormat(ts)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+ else if (!(s->s_x = SDL_DisplayFormat(zs)))
+ {
+ fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError());
+ goto end;
+ }
+
+ gfx_register_sprite(s);
+ s->w = ts->w;
+ s->h = ts->h;
+ ret = 0;
+
+end:
+ SDL_FreeRW(ops);
+ SDL_FreeSurface(ts);
+ SDL_FreeSurface(zs);
+ return ret;
+}
+
+int sprite_from_fp(struct gfx_sprite *const s, FILE *const f)
+{
+ *s = (const struct gfx_sprite){0};
+
+ if (load_header(s, f) || load_bitmap(s, f))
+ return -1;
+
+ return 0;
+}
+
+void sprite_sort(struct gfx_sprite *const s)
+{
+ SDL_Rect r =
+ {
+ .x = s->x,
+ .y = s->y
+ };
+
+ SDL_Rect clip =
+ {
+ .x = s->u,
+ .y = s->v,
+ .w = s->w,
+ .h = s->h
+ };
+
+ if (SDL_BlitSurface(s->s, &clip, gfx_screen(), &r))
+ fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError());
+}
diff --git a/src/gfx/src/CMakeLists.txt b/src/gfx/src/CMakeLists.txt
new file mode 100644
index 0000000..b62fca4
--- /dev/null
+++ b/src/gfx/src/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(gfx PRIVATE
+ dim.c
+ update.c
+)
diff --git a/src/gfx/src/dim.c b/src/gfx/src/dim.c
new file mode 100644
index 0000000..5413469
--- /dev/null
+++ b/src/gfx/src/dim.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/private.h>
+
+int screen_w = SCREEN_W, screen_h = SCREEN_H;
diff --git a/src/gfx/src/update.c b/src/gfx/src/update.c
new file mode 100644
index 0000000..95980f9
--- /dev/null
+++ b/src/gfx/src/update.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <gfx/gfx.h>
+
+int gfx_update(void)
+{
+ if (!gfx_ready())
+ return 0;
+
+ return gfx_draw();
+}
diff --git a/src/init/CMakeLists.txt b/src/init/CMakeLists.txt
new file mode 100644
index 0000000..d9b70b0
--- /dev/null
+++ b/src/init/CMakeLists.txt
@@ -0,0 +1,34 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(init)
+add_subdirectory(src)
+target_include_directories(init PUBLIC include PRIVATE private_include)
+target_link_libraries(init PRIVATE
+ aio
+ devfs
+ drv
+ io
+ kprintf
+ loop
+ rootfs
+ iso9660
+)
+
+if(PS1_BUILD)
+ add_subdirectory(ps1)
+ target_link_libraries(init PRIVATE init_ps1)
+endif()
diff --git a/src/init/include/init.h b/src/init/include/init.h
new file mode 100644
index 0000000..a1050ab
--- /dev/null
+++ b/src/init/include/init.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef INIT_H
+#define INIT_H
+
+int init_time(void);
+int init_port(void);
+int init_boot(void);
+int init_vfs(void);
+int init_run(void);
+
+#endif
diff --git a/src/init/private_include/init/port.h b/src/init/private_include/init/port.h
new file mode 100644
index 0000000..7211534
--- /dev/null
+++ b/src/init/private_include/init/port.h
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef INIT_PORT_H
+#define INIT_PORT_H
+
+int init_port_boot(void);
+int init_port_run(void);
+
+#endif
diff --git a/src/init/private_include/init/types.h b/src/init/private_include/init/types.h
new file mode 100644
index 0000000..7f6114d
--- /dev/null
+++ b/src/init/private_include/init/types.h
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef INIT_TYPES_H
+#define INIT_TYPES_H
+
+#include <aio.h>
+#include <sys/stat.h>
+#include <time.h>
+
+struct init
+{
+ struct aio *aio;
+ struct stat sb;
+ unsigned retries;
+ struct timespec last_retry;
+ int (*next)(struct init *);
+};
+
+extern struct init init_vars;
+
+#endif
diff --git a/src/init/ps1/CMakeLists.txt b/src/init/ps1/CMakeLists.txt
new file mode 100644
index 0000000..21df5d7
--- /dev/null
+++ b/src/init/ps1/CMakeLists.txt
@@ -0,0 +1,37 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(init_ps1)
+add_subdirectory(src)
+target_include_directories(init_ps1 PRIVATE private_include)
+target_link_libraries(init_ps1
+ PUBLIC
+ c
+ init
+ PRIVATE
+ aio
+ bin
+ drv_ps1_bios
+ drv_ps1_cpu
+ drv_ps1_irq
+ drv_ps1_rcnt
+ drv_ps1_time
+ iso9660
+ kprintf
+ loop
+ net
+ state
+)
diff --git a/src/init/ps1/private_include/init/ps1/types.h b/src/init/ps1/private_include/init/ps1/types.h
new file mode 100644
index 0000000..66702d1
--- /dev/null
+++ b/src/init/ps1/private_include/init/ps1/types.h
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef INIT_PS1_TYPES_H
+#define INIT_PS1_TYPES_H
+
+#include <aio.h>
+#include <sys/stat.h>
+#include <time.h>
+
+struct init_ps1
+{
+ struct aio *aio;
+ struct stat *sb;
+ unsigned retries;
+ const char *path;
+ struct timespec last_retry;
+ int (*next)(struct init_ps1 *);
+ int (*success)(struct init_ps1 *);
+ int (*retry)(struct init_ps1 *);
+};
+
+extern struct init_ps1 init_ps1;
+
+#endif
diff --git a/src/init/ps1/src/CMakeLists.txt b/src/init/ps1/src/CMakeLists.txt
new file mode 100644
index 0000000..68dab00
--- /dev/null
+++ b/src/init/ps1/src/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(init_ps1 PRIVATE
+ boot.c
+ globalvars.c
+ port.c
+ run.c
+ time.c
+)
diff --git a/src/init/ps1/src/boot.c b/src/init/ps1/src/boot.c
new file mode 100644
index 0000000..062078c
--- /dev/null
+++ b/src/init/ps1/src/boot.c
@@ -0,0 +1,251 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init.h>
+#include <init/ps1/types.h>
+#include <aio.h>
+#include <bin.h>
+#include <iso9660.h>
+#include <kprintf.h>
+#include <loop.h>
+#include <net.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <state.h>
+#include <time.h>
+
+struct boot
+{
+ struct aio *aio;
+ struct init_ps1 *p;
+};
+
+enum {RETRIES = 5};
+static const char serial[] = "/dev/ttyS0";
+
+static int retry_cd(struct init_ps1 *);
+
+static int wait_retry(struct init_ps1 *const p)
+{
+ struct timespec ts;
+ const time_t last = p->last_retry.tv_sec, timeout = 5;
+
+ if (clock_gettime(CLOCK_REALTIME, &ts))
+ return -1;
+ else if (ts.tv_sec - last >= timeout)
+ p->next = p->retry;
+
+ return 0;
+}
+
+static int stat_done(const enum state s, void *const args)
+{
+ int ret = 0;
+ struct init_ps1 *const p = args;
+
+ if (s)
+ {
+ struct timespec ts;
+
+ if (!--p->retries || clock_gettime(CLOCK_REALTIME, &ts))
+ {
+ ret = -1;
+ goto end;
+ }
+
+ p->last_retry = ts;
+ p->next = wait_retry;
+ }
+ else
+ {
+ p->next = p->success;
+ kprintf("Successfully initialized %s (took %u attempts)\n",
+ p->path, RETRIES - p->retries + 1);
+ }
+
+end:
+ loop_rm_aio(p->aio);
+ aio_free(p->aio);
+ free(p->sb);
+ return ret;
+}
+
+static int mount_done(const enum state state, void *const args)
+{
+ struct boot *const b = args;
+
+ if (loop_rm_aio(b->aio))
+ return -1;
+
+ aio_free(b->aio);
+ free(b);
+
+ if (state)
+ kprintf("Failed to mount ISO9660 filesystem\n");
+ else
+ {
+ const char *const args[] = {NULL};
+
+ kprintf("ISO9660 filesystem mounted successfully\n");
+ kprintf("Opening second-stage initd\n");
+
+ /* TODO: create symbolic from /mnt/cdrom/bin to /bin */
+ return bin_exec("/mnt/cdrom/bin/initd", args, 0, 0);
+ }
+
+ return 0;
+}
+
+static int mount_cd(struct init_ps1 *const p)
+{
+ struct aio *aio = NULL;
+ struct boot *const b = malloc(sizeof *b);
+
+ if (!b)
+ goto failure;
+
+ const struct aio_mount fm =
+ {
+ .mount =
+ {
+ .src = "/dev/cd0",
+ .tgt = "/mnt/cdrom",
+ .mode = 0755
+ },
+
+ .type = "iso9660"
+ };
+
+ const struct aio_done d =
+ {
+ .args = b,
+ .f = mount_done
+ };
+
+ if (!(aio = aio_mount(&fm, &d)) || loop_add_aio(aio))
+ goto failure;
+
+ p->next = NULL;
+ *b = (const struct boot){.aio = aio, .p = p};
+ kprintf("Mounting ISO9660 filesystem from %s to %s\n",
+ fm.mount.src, fm.mount.tgt);
+ return 0;
+
+failure:
+ kprintf("Failed to mount ISO9660 filesystem\n");
+ aio_free(aio);
+ free(b);
+ return -1;
+}
+
+static int retry_cd(struct init_ps1 *const p)
+{
+ static const char path[] = "/dev/cd0";
+ struct aio *aio = NULL;
+ struct stat *const sb = malloc(sizeof *sb);
+
+ if (!sb)
+ goto failure;
+
+ const struct fs_stat s = {.path = path, .sb = sb};
+ const struct aio_done d = {.f = stat_done, .args = p};
+ const unsigned retries = p->retries;
+
+ if (!(aio = aio_stat(&s, &d)) || loop_add_aio(aio))
+ goto failure;
+
+ *p = (const struct init_ps1)
+ {
+ .aio = aio,
+ .sb = sb,
+ .path = path,
+ .retries = retries,
+ .success = mount_cd,
+ .last_retry = {.tv_sec = (time_t)-1}
+ };
+
+ p->next = NULL;
+ kprintf("Initializing CD-ROM to %s (attempt %u)\n", path,
+ RETRIES - p->retries + 1);
+ return 0;
+
+failure:
+ free(aio);
+ free(sb);
+ return -1;
+}
+
+static int init_net(struct init_ps1 *const p)
+{
+ if (net_init(serial))
+ return -1;
+
+ p->next = retry_cd;
+ return 0;
+}
+
+static int retry_serial(struct init_ps1 *const p)
+{
+ struct aio *aio = NULL;
+ struct stat *const sb = malloc(sizeof *sb);
+
+ if (!sb)
+ goto failure;
+
+ const struct fs_stat s = {.path = serial, .sb = sb};
+ const struct aio_done d = {.f = stat_done, .args = p};
+ const unsigned retries = p->retries;
+
+ if (!(aio = aio_stat(&s, &d)) || loop_add_aio(aio))
+ goto failure;
+
+ *p = (const struct init_ps1)
+ {
+ .aio = aio,
+ .sb = sb,
+ .path = serial,
+ .retries = retries,
+ .success = init_net,
+ .last_retry = {.tv_sec = (time_t)-1}
+ };
+
+ p->next = NULL;
+ kprintf("Initializing serial device to %s (attempt %u)\n", serial,
+ RETRIES - p->retries + 1);
+ return 0;
+
+failure:
+ free(aio);
+ free(sb);
+ return -1;
+}
+
+int init_port_boot(void)
+{
+ if (iso9660_register())
+ return -1;
+
+ init_ps1 = (const struct init_ps1)
+ {
+ .retries = RETRIES,
+ .next = retry_serial
+ };
+
+ return 0;
+}
diff --git a/src/init/ps1/src/globalvars.c b/src/init/ps1/src/globalvars.c
new file mode 100644
index 0000000..fcf6a6c
--- /dev/null
+++ b/src/init/ps1/src/globalvars.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init/ps1/types.h>
+
+struct init_ps1 init_ps1;
diff --git a/src/init/ps1/src/port.c b/src/init/ps1/src/port.c
new file mode 100644
index 0000000..9bc2a8e
--- /dev/null
+++ b/src/init/ps1/src/port.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/irq.h>
+
+int init_port(void)
+{
+ EnterCriticalSection();
+ SetConf(16, 1, (void *)0x801ff800);
+ ExitCriticalSection();
+
+ return drv_ps1_irq_init();
+}
diff --git a/src/init/ps1/src/run.c b/src/init/ps1/src/run.c
new file mode 100644
index 0000000..bc4b645
--- /dev/null
+++ b/src/init/ps1/src/run.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init.h>
+#include <init/ps1/types.h>
+
+int init_port_run(void)
+{
+ struct init_ps1 *const p = &init_ps1;
+
+ return p->next ? p->next(p) : 0;
+}
diff --git a/src/init/ps1/src/time.c b/src/init/ps1/src/time.c
new file mode 100644
index 0000000..1978945
--- /dev/null
+++ b/src/init/ps1/src/time.c
@@ -0,0 +1,47 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init.h>
+#include <init/ps1/types.h>
+#include <drv/ps1/bios.h>
+#include <drv/ps1/cpu.h>
+#include <drv/ps1/rcnt.h>
+#include <drv/ps1/time.h>
+#include <time.h>
+
+int init_time(void)
+{
+ struct timespec ts;
+ const union drv_ps1_rcnt_cfg cfg =
+ {
+ .bits =
+ {
+ .reset = 1,
+ .repeat = 1,
+ .irq_tgt = 1,
+ .clocksrc = 3
+ }
+ };
+
+ if (clock_getres(CLOCK_REALTIME, &ts))
+ return -1;
+
+ const uint16_t target = (DRV_PS1_CPU_F / 8) / (ts.tv_nsec / 1000);
+
+ return drv_ps1_rcnt_init(DRV_PS1_RCNT2, target, &cfg, drv_ps1_time_tick);
+}
diff --git a/src/init/src/CMakeLists.txt b/src/init/src/CMakeLists.txt
new file mode 100644
index 0000000..ac94d56
--- /dev/null
+++ b/src/init/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(init PRIVATE
+ boot.c
+ run.c
+ vars.c
+ vfs.c
+)
diff --git a/src/init/src/boot.c b/src/init/src/boot.c
new file mode 100644
index 0000000..30d9a9e
--- /dev/null
+++ b/src/init/src/boot.c
@@ -0,0 +1,121 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init.h>
+#include <init/port.h>
+#include <init/types.h>
+#include <aio.h>
+#include <kprintf.h>
+#include <loop.h>
+#include <stdlib.h>
+#include <time.h>
+
+static int retry(struct init *);
+enum {RETRIES = 5};
+
+static int run(struct init *const init)
+{
+ return init_port_run();
+}
+
+static int port(struct init *const init)
+{
+ kprintf("tty initilization successful (took %u attempts)\n",
+ RETRIES - init->retries + 1);
+
+ if (init_port_boot())
+ return -1;
+
+ init->next = run;
+ return 0;
+}
+
+static int wait_retry(struct init *const init)
+{
+ struct timespec ts;
+ const time_t last = init->last_retry.tv_sec, timeout = 5;
+
+ if (clock_gettime(CLOCK_REALTIME, &ts))
+ return -1;
+ else if (ts.tv_sec - last >= timeout)
+ init->next = retry;
+
+ return 0;
+}
+
+static int stat_done(const enum state s, void *const args)
+{
+ int ret = 0;
+ struct init *const init = args;
+
+ if (s)
+ {
+ struct timespec ts;
+
+ if (!--init->retries || clock_gettime(CLOCK_REALTIME, &ts))
+ {
+ ret = -1;
+ goto end;
+ }
+
+ init->last_retry = ts;
+ init->next = wait_retry;
+ }
+ else
+ init->next = port;
+
+end:
+ loop_rm_aio(init->aio);
+ aio_free(init->aio);
+ return ret;
+}
+
+static int retry(struct init *const init)
+{
+ struct aio *aio = NULL;
+ const struct fs_stat s = {.path = "/dev/tty", .sb = &init->sb};
+ const struct aio_done d = {.f = stat_done, .args = init};
+ const unsigned retries = init->retries;
+
+ if (!(aio = aio_stat(&s, &d)) || loop_add_aio(aio))
+ goto failure;
+
+ *init = (const struct init)
+ {
+ .aio = aio,
+ .retries = retries,
+ .last_retry = {.tv_sec = (time_t)-1}
+ };
+
+ return 0;
+
+failure:
+ free(aio);
+ return -1;
+}
+
+int init_boot(void)
+{
+ init_vars = (const struct init)
+ {
+ .retries = RETRIES,
+ .next = retry
+ };
+
+ return 0;
+}
diff --git a/src/init/src/run.c b/src/init/src/run.c
new file mode 100644
index 0000000..9fa643d
--- /dev/null
+++ b/src/init/src/run.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init.h>
+#include <init/types.h>
+
+int init_run(void)
+{
+ struct init *const p = &init_vars;
+
+ return p->next ? p->next(p) : 0;
+}
diff --git a/src/init/src/vars.c b/src/init/src/vars.c
new file mode 100644
index 0000000..10d4858
--- /dev/null
+++ b/src/init/src/vars.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init/types.h>
+
+struct init init_vars;
diff --git a/src/init/src/vfs.c b/src/init/src/vfs.c
new file mode 100644
index 0000000..6fe0904
--- /dev/null
+++ b/src/init/src/vfs.c
@@ -0,0 +1,86 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <init.h>
+#include <aio.h>
+#include <drv/drv.h>
+#include <io.h>
+#include <devfs.h>
+#include <rootfs.h>
+#include <iso9660.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+int init_vfs(void)
+{
+ static const struct aio_mount m[] =
+ {
+ {
+ .mount =
+ {
+ .tgt = "/",
+ .mode = 0755
+ },
+
+ .type = "rootfs"
+ },
+
+ {
+ .mount =
+ {
+ .tgt = "/dev",
+ .mode = 0755
+ },
+
+ .type = "devfs"
+ }
+ };
+
+ static const struct fs_mkdir mk[] =
+ {
+ {
+ .path = "/dev",
+ .mode = 0755
+ },
+
+ {
+ .path = "/mnt",
+ .mode = 0755
+ },
+
+ {
+ .path = "/mnt/cdrom",
+ .mode = 0755
+ }
+ };
+
+ if (rootfs_register()
+ || devfs_register()
+ || io_mount(m))
+ return -1;
+
+ for (size_t i = 0; i < sizeof mk / sizeof *mk; i++)
+ if (io_mkdir(&mk[i]))
+ return -1;
+
+ for (size_t i = 1; i < sizeof m / sizeof *m; i++)
+ if (io_mount(&m[i]))
+ return -1;
+
+ return 0;
+}
diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt
new file mode 100644
index 0000000..9418e9e
--- /dev/null
+++ b/src/io/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(io)
+add_subdirectory(src)
+target_include_directories(io PUBLIC include)
+target_link_libraries(io PUBLIC aio)
diff --git a/src/io/include/io.h b/src/io/include/io.h
new file mode 100644
index 0000000..0a3a3de
--- /dev/null
+++ b/src/io/include/io.h
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef IO_H
+#define IO_H
+
+#include <aio.h>
+#include <sys/types.h>
+
+int io_mkdir(const struct fs_mkdir *m);
+int io_mount(const struct aio_mount *m);
+int io_open(const struct fs_open *o);
+int io_write(const struct fs_write *w);
+
+#endif
diff --git a/src/io/src/CMakeLists.txt b/src/io/src/CMakeLists.txt
new file mode 100644
index 0000000..4c8b2f5
--- /dev/null
+++ b/src/io/src/CMakeLists.txt
@@ -0,0 +1,6 @@
+target_sources(io PRIVATE
+ mkdir.c
+ mount.c
+ open.c
+ write.c
+)
diff --git a/src/io/src/mkdir.c b/src/io/src/mkdir.c
new file mode 100644
index 0000000..fc141bb
--- /dev/null
+++ b/src/io/src/mkdir.c
@@ -0,0 +1,40 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <io.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <errno.h>
+
+int io_mkdir(const struct fs_mkdir *const m)
+{
+ int ret = 0;
+ struct aio *const aio = aio_mkdir(m, NULL);
+ struct aio_poll p = {.aio = aio};
+
+ if (!aio || aio_poll(&p, -1) < 0 || p.error)
+ {
+ ret = -1;
+
+ if (p.error)
+ errno = p.error;
+ }
+
+ aio_free(aio);
+ return ret;
+}
diff --git a/src/io/src/mount.c b/src/io/src/mount.c
new file mode 100644
index 0000000..e8a1af9
--- /dev/null
+++ b/src/io/src/mount.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <io.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int io_mount(const struct aio_mount *const m)
+{
+ int ret = 0;
+ struct aio *const aio = aio_mount(m, NULL);
+ struct aio_poll p = {.aio = aio};
+
+ if (!aio || aio_poll(&p, -1) < 0 || p.error)
+ ret = -1;
+
+ aio_free(aio);
+ return ret;
+}
diff --git a/src/io/src/open.c b/src/io/src/open.c
new file mode 100644
index 0000000..89b1fe9
--- /dev/null
+++ b/src/io/src/open.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <io.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int io_open(const struct fs_open *const o)
+{
+ int ret = 0;
+ struct aio *const aio = aio_open(o, NULL);
+ struct aio_poll p = {.aio = aio};
+
+ if (!aio || aio_poll(&p, -1) < 0 || p.error)
+ ret = -1;
+
+ aio_free(aio);
+ return ret;
+}
diff --git a/src/io/src/write.c b/src/io/src/write.c
new file mode 100644
index 0000000..7e8f70f
--- /dev/null
+++ b/src/io/src/write.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <io.h>
+#include <aio.h>
+#include <fs/fs.h>
+#include <stddef.h>
+
+int io_write(const struct fs_write *const w)
+{
+ int ret = 0;
+ struct aio *const aio = aio_write(w, NULL);
+ struct aio_poll p = {.aio = aio};
+
+ if (!aio || aio_poll(&p, -1) < 0 || p.error)
+ ret = -1;
+
+ aio_free(aio);
+ return ret;
+}
diff --git a/src/kprintf/CMakeLists.txt b/src/kprintf/CMakeLists.txt
new file mode 100644
index 0000000..fcc53c9
--- /dev/null
+++ b/src/kprintf/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(kprintf)
+add_subdirectory(src)
+target_include_directories(kprintf PUBLIC include PRIVATE private_include)
+target_link_libraries(kprintf PUBLIC c PRIVATE io nanowasm)
diff --git a/src/kprintf/include/kprintf.h b/src/kprintf/include/kprintf.h
new file mode 100644
index 0000000..fb0710f
--- /dev/null
+++ b/src/kprintf/include/kprintf.h
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef KPRINTF_H
+#define KPRINTF_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#if __GNUC__
+#define KPRINTF_ATTR __attribute__ ((format (__printf__, 1, 2)))
+#define KTPRINTF_ATTR __attribute__ ((format (__printf__, 2, 3)))
+#else
+#define KPRINTF_ATTR
+#define KTPRINTF_ATTR
+#endif
+
+int kprintf(const char *fmt, ...) KPRINTF_ATTR;
+int ktprintf(bool time, const char *fmt, ...);
+int kvprintf(const char *fmt, va_list va);
+int ktvprintf(bool time, const char *fmt, va_list va);
+
+#endif
diff --git a/src/kprintf/src/CMakeLists.txt b/src/kprintf/src/CMakeLists.txt
new file mode 100644
index 0000000..6bdfbc7
--- /dev/null
+++ b/src/kprintf/src/CMakeLists.txt
@@ -0,0 +1,26 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(kprintf PRIVATE
+ kprintf.c
+ kvprintf.c
+ ktprintf.c
+ ktvprintf.c
+ nwp_log.c
+ wip_log.c
+)
+
+target_link_libraries(kprintf PRIVATE nanowasm wip)
diff --git a/src/kprintf/src/kprintf.c b/src/kprintf/src/kprintf.c
new file mode 100644
index 0000000..de90e59
--- /dev/null
+++ b/src/kprintf/src/kprintf.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <kprintf.h>
+#include <io.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <printf.h>
+
+int kprintf(const char *const fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = kvprintf(fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/src/kprintf/src/ktprintf.c b/src/kprintf/src/ktprintf.c
new file mode 100644
index 0000000..f619d54
--- /dev/null
+++ b/src/kprintf/src/ktprintf.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <kprintf.h>
+#include <io.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <printf.h>
+
+int ktprintf(const bool time, const char *const fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = ktvprintf(time, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/src/kprintf/src/ktvprintf.c b/src/kprintf/src/ktvprintf.c
new file mode 100644
index 0000000..a3529c4
--- /dev/null
+++ b/src/kprintf/src/ktvprintf.c
@@ -0,0 +1,80 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <kprintf.h>
+#include <io.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <printf.h>
+#include <time.h>
+
+struct kvprintf
+{
+ struct fs_fd fd;
+ size_t n;
+};
+
+static void writechar(const char c, void *const args)
+{
+ static char buf[128];
+ static size_t bufi;
+ struct kvprintf *k = args;
+
+ buf[bufi++] = c;
+
+ if (c == '\n' || bufi >= sizeof buf)
+ {
+ const struct fs_write w =
+ {
+ .buf = buf,
+ .fd = &k->fd,
+ .n = bufi
+ };
+
+ io_write(&w);
+ bufi = 0;
+ }
+
+ k->n++;
+}
+
+int ktvprintf(const bool time, const char *const fmt, va_list ap)
+{
+ struct timespec ts;
+ struct kvprintf k = {0};
+ const struct fs_open o =
+ {
+ .fd = &k.fd,
+ .path = "/dev/tty",
+ .mode = O_WRONLY
+ };
+
+ if (time && clock_gettime(CLOCK_REALTIME, &ts))
+ return -1;
+
+ const long ms = ts.tv_nsec / 1000000;
+
+ if (io_open(&o)
+ || (time
+ && fctprintf(writechar, &k, "[%lld.%03ld] ", ts.tv_sec, ms) < 0)
+ || fctvprintf(writechar, &k, fmt, ap) < 0)
+ return -1;
+
+ return k.n;
+}
diff --git a/src/kprintf/src/kvprintf.c b/src/kprintf/src/kvprintf.c
new file mode 100644
index 0000000..69890cb
--- /dev/null
+++ b/src/kprintf/src/kvprintf.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <kprintf.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+int kvprintf(const char *fmt, va_list va)
+{
+ return ktvprintf(true, fmt, va);
+}
diff --git a/src/kprintf/src/nwp_log.c b/src/kprintf/src/nwp_log.c
new file mode 100644
index 0000000..2db9969
--- /dev/null
+++ b/src/kprintf/src/nwp_log.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <kprintf.h>
+#include <nanowasm/nw.h>
+#include <stdarg.h>
+
+int nwp_log(const char *const fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = ktvprintf(false, fmt, ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/src/kprintf/src/wip_log.c b/src/kprintf/src/wip_log.c
new file mode 100644
index 0000000..67f4f8f
--- /dev/null
+++ b/src/kprintf/src/wip_log.c
@@ -0,0 +1,44 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <kprintf.h>
+#include <wip/wip.h>
+#include <stdarg.h>
+
+
+#include <drv/ps1/bios.h>
+#include <dynstr.h>
+int wip_log(const char *const fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+#if 1
+ ret = ktvprintf(false, fmt, ap);
+#else
+ struct dynstr d;
+ dynstr_init(&d);
+ if (dynstr_vappend(&d, fmt, ap)) ret = -1;
+ else
+ ret = Printf("%s", d.str);
+ dynstr_free(&d);
+#endif
+ va_end(ap);
+ return ret;
+}
diff --git a/src/libc/CMakeLists.txt b/src/libc/CMakeLists.txt
index 952df35..309e47a 100644
--- a/src/libc/CMakeLists.txt
+++ b/src/libc/CMakeLists.txt
@@ -1,4 +1,4 @@
-# wanix, a Unix-like operating system for WebAssembly
+# wnix, a Unix-like operating system for WebAssembly applications.
# Copyright (C) 2025 Xavier Del Campo Romero
#
# This program is free software: you can redistribute it and/or modify
@@ -15,16 +15,17 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
set(src
- "src/errno.c"
- "src/free.c"
- "src/malloc.c"
- "src/memcmp.c"
- "src/memcpy.c"
- "src/memset.c"
- "src/strchr.c"
- "src/streams.c"
- "src/strerror.c"
- "src/strlen.c"
+ printf/printf.c
+ tinyalloc/tinyalloc.c
)
add_library(c ${src})
-target_include_directories(c PUBLIC "include" PRIVATE "private_include")
+add_subdirectory(src)
+add_subdirectory(newlib)
+target_include_directories(c PUBLIC include printf
+ PRIVATE private_include tinyalloc)
+
+target_compile_definitions(c PRIVATE TA_DISABLE_SPLIT TA_DISABLE_COMPACT)
+
+if(NOT LIBC_FREESTANDING)
+ target_link_libraries(c PRIVATE aio fs drv)
+endif()
diff --git a/src/libc/COPYING.NEWLIB b/src/libc/COPYING.NEWLIB
new file mode 100644
index 0000000..9a2680d
--- /dev/null
+++ b/src/libc/COPYING.NEWLIB
@@ -0,0 +1,1572 @@
+The newlib subdirectory is a collection of software from several sources.
+
+Each file may have its own copyright/license that is embedded in the source
+file. Unless otherwise noted in the body of the source file(s), the following copyright
+notices will apply to the contents of the newlib subdirectory:
+
+(1) Red Hat Incorporated
+
+Copyright (c) 1994-2009 Red Hat, Inc. All rights reserved.
+
+This copyrighted material is made available to anyone wishing to use,
+modify, copy, or redistribute it subject to the terms and conditions
+of the BSD License. This program is distributed in the hope that
+it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
+including the implied warranties of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. A copy of this license is available at
+http://www.opensource.org/licenses. Any Red Hat trademarks that are
+incorporated in the source code or documentation are not subject to
+the BSD License and may only be used or replicated with the express
+permission of Red Hat, Inc.
+
+(2) University of California, Berkeley
+
+Copyright (c) 1981-2000 The Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
+(3) David M. Gay (AT&T 1991, Lucent 1998)
+
+The author of this software is David M. Gay.
+
+Copyright (c) 1991 by AT&T.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose without fee is hereby granted, provided that this entire notice
+is included in all copies of any software which is or includes a copy
+or modification of this software and in all copies of the supporting
+documentation for such software.
+
+THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY
+REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+
+-------------------------------------------------------------------
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2001 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+
+(4) Advanced Micro Devices
+
+Copyright 1989, 1990 Advanced Micro Devices, Inc.
+
+This software is the property of Advanced Micro Devices, Inc (AMD) which
+specifically grants the user the right to modify, use and distribute this
+software provided this notice is not removed or altered. All other rights
+are reserved by AMD.
+
+AMD MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS
+SOFTWARE. IN NO EVENT SHALL AMD BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL
+DAMAGES IN CONNECTION WITH OR ARISING FROM THE FURNISHING, PERFORMANCE, OR
+USE OF THIS SOFTWARE.
+
+So that all may benefit from your experience, please report any problems
+or suggestions about this software to the 29K Technical Support Center at
+800-29-29-AMD (800-292-9263) in the USA, or 0800-89-1131 in the UK, or
+0031-11-1129 in Japan, toll free. The direct dial number is 512-462-4118.
+
+Advanced Micro Devices, Inc.
+29K Support Products
+Mail Stop 573
+5900 E. Ben White Blvd.
+Austin, TX 78741
+800-292-9263
+
+(5)
+
+(6)
+
+(7) Sun Microsystems
+
+Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+
+Developed at SunPro, a Sun Microsystems, Inc. business.
+Permission to use, copy, modify, and distribute this
+software is freely granted, provided that this notice is preserved.
+
+(8) Hewlett Packard
+
+(c) Copyright 1986 HEWLETT-PACKARD COMPANY
+
+To anyone who acknowledges that this file is provided "AS IS"
+without any express or implied warranty:
+ permission to use, copy, modify, and distribute this file
+for any purpose is hereby granted without fee, provided that
+the above copyright notice and this notice appears in all
+copies, and that the name of Hewlett-Packard Company not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+Hewlett-Packard Company makes no representations about the
+suitability of this software for any purpose.
+
+(9) Hans-Peter Nilsson
+
+Copyright (C) 2001 Hans-Peter Nilsson
+
+Permission to use, copy, modify, and distribute this software is
+freely granted, provided that the above copyright notice, this notice
+and the following disclaimer are preserved with no changes.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+(10) Stephane Carrez (m68hc11-elf/m68hc12-elf targets only)
+
+Copyright (C) 1999, 2000, 2001, 2002 Stephane Carrez (stcarrez@nerim.fr)
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+(11) Christopher G. Demetriou
+
+Copyright (c) 2001 Christopher G. Demetriou
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(12) SuperH, Inc.
+
+Copyright 2002 SuperH, Inc. All rights reserved
+
+This software is the property of SuperH, Inc (SuperH) which specifically
+grants the user the right to modify, use and distribute this software
+provided this notice is not removed or altered. All other rights are
+reserved by SuperH.
+
+SUPERH MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO
+THIS SOFTWARE. IN NO EVENT SHALL SUPERH BE LIABLE FOR INDIRECT, SPECIAL,
+INCIDENTAL OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING FROM
+THE FURNISHING, PERFORMANCE, OR USE OF THIS SOFTWARE.
+
+So that all may benefit from your experience, please report any problems
+or suggestions about this software to the SuperH Support Center via
+e-mail at softwaresupport@superh.com .
+
+SuperH, Inc.
+405 River Oaks Parkway
+San Jose
+CA 95134
+USA
+
+(13) Royal Institute of Technology
+
+Copyright (c) 1999 Kungliga Tekniska Högskolan
+(Royal Institute of Technology, Stockholm, Sweden).
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. Neither the name of KTH nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(14) Alexey Zelkin
+
+Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(15) Andrey A. Chernov
+
+Copyright (C) 1997 by Andrey A. Chernov, Moscow, Russia.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(16) FreeBSD
+
+Copyright (c) 1997-2002 FreeBSD Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(17) S. L. Moshier
+
+Author: S. L. Moshier.
+
+Copyright (c) 1984,2000 S.L. Moshier
+
+Permission to use, copy, modify, and distribute this software for any
+purpose without fee is hereby granted, provided that this entire notice
+is included in all copies of any software which is or includes a copy
+or modification of this software and in all copies of the supporting
+documentation for such software.
+
+THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION
+OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
+SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+
+(18) Citrus Project
+
+Copyright (c)1999 Citrus Project,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(19) Todd C. Miller
+
+Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(20) DJ Delorie (i386 / arm)
+Copyright (C) 1991 DJ Delorie
+All rights reserved.
+
+Redistribution, modification, and use in source and binary forms is permitted
+provided that the above copyright notice and following paragraph are
+duplicated in all such forms.
+
+This file is distributed WITHOUT ANY WARRANTY; without even the implied
+warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+(21) Free Software Foundation LGPL License (*-linux* targets only)
+
+ Copyright (C) 1990-1999, 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+(22) Xavier Leroy LGPL License (i[3456]86-*-linux* targets only)
+
+Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Library General Public License for more details.
+
+(23) Intel (i960)
+
+Copyright (c) 1993 Intel Corporation
+
+Intel hereby grants you permission to copy, modify, and distribute this
+software and its documentation. Intel grants this permission provided
+that the above copyright notice appears in all copies and that both the
+copyright notice and this permission notice appear in supporting
+documentation. In addition, Intel grants this permission provided that
+you prominently mark as "not part of the original" any modifications
+made to this software or documentation, and that the name of Intel
+Corporation not be used in advertising or publicity pertaining to
+distribution of the software or the documentation without specific,
+written prior permission.
+
+Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR
+IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Intel makes no guarantee or
+representations regarding the use of, or the results of the use of,
+the software and documentation in terms of correctness, accuracy,
+reliability, currentness, or otherwise; and you rely on the software,
+documentation and results solely at your own risk.
+
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
+LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
+OF ANY KIND. IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM
+PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER.
+
+(24) Hewlett-Packard (hppa targets only)
+
+(c) Copyright 1986 HEWLETT-PACKARD COMPANY
+
+To anyone who acknowledges that this file is provided "AS IS"
+without any express or implied warranty:
+ permission to use, copy, modify, and distribute this file
+for any purpose is hereby granted without fee, provided that
+the above copyright notice and this notice appears in all
+copies, and that the name of Hewlett-Packard Company not be
+used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+Hewlett-Packard Company makes no representations about the
+suitability of this software for any purpose.
+
+(25) Henry Spencer (only *-linux targets)
+
+Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved.
+This software is not subject to any license of the American Telephone
+and Telegraph Company or of the Regents of the University of California.
+
+Permission is granted to anyone to use this software for any purpose on
+any computer system, and to alter it and redistribute it, subject
+to the following restrictions:
+
+1. The author is not responsible for the consequences of use of this
+ software, no matter how awful, even if they arise from flaws in it.
+
+2. The origin of this software must not be misrepresented, either by
+ explicit claim or by omission. Since few users ever read sources,
+ credits must appear in the documentation.
+
+3. Altered versions must be plainly marked as such, and must not be
+ misrepresented as being the original software. Since few users
+ ever read sources, credits must appear in the documentation.
+
+4. This notice may not be removed or altered.
+
+(26) Mike Barcroft
+
+Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(27) Konstantin Chuguev (--enable-newlib-iconv)
+
+Copyright (c) 1999, 2000
+ Konstantin Chuguev. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+ iconv (Charset Conversion Library) v2.0
+
+(28) Artem Bityuckiy (--enable-newlib-iconv)
+
+Copyright (c) 2003, Artem B. Bityuckiy, SoftMine Corporation.
+Rights transferred to Franklin Electronic Publishers.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(29) IBM, Sony, Toshiba (only spu-* targets)
+
+ (C) Copyright 2001,2006,
+ International Business Machines Corporation,
+ Sony Computer Entertainment, Incorporated,
+ Toshiba Corporation,
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the names of the copyright holders nor the names of their
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+(30) - Alex Tatmanjants (targets using libc/posix)
+
+ Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ at Electronni Visti IA, Kiev, Ukraine.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+(31) - M. Warner Losh (targets using libc/posix)
+
+ Copyright (c) 1998, M. Warner Losh <imp@freebsd.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+(32) - Andrey A. Chernov (targets using libc/posix)
+
+ Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+(33) - Daniel Eischen (targets using libc/posix)
+
+ Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+
+(34) - Jon Beniston (only lm32-* targets)
+
+ Contributed by Jon Beniston <jon@beniston.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+
+(35) - Arm Ltd
+
+ SPDX-License-Identifier: BSD-3-Clause
+
+ Copyright (c) 2009-2022 Arm Ltd
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the company may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(36) - Xilinx, Inc. (microblaze-* and powerpc-* targets)
+
+Copyright (c) 2004, 2009 Xilinx, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Neither the name of Xilinx nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+(37) Texas Instruments Incorporated (tic6x-*, *-tirtos targets)
+
+Copyright (c) 1996-2010,2014 Texas Instruments Incorporated
+http://www.ti.com/
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ Neither the name of Texas Instruments Incorporated nor the names
+ of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(38) National Semiconductor (cr16-* and crx-* targets)
+
+Copyright (c) 2004 National Semiconductor Corporation
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+(39) - Adapteva, Inc. (epiphany-* targets)
+
+Copyright (c) 2011, Adapteva, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Adapteva nor the names of its contributors may be used
+ to endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(40) - Altera Corportion (nios2-* targets)
+
+Copyright (c) 2003 Altera Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ o Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ o Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ o Neither the name of Altera Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY ALTERA CORPORATION, THE COPYRIGHT HOLDER,
+AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(41) Ed Schouten - Free BSD
+
+Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(42) - Rolls-Royce Controls and Data Services Limited (visium-* targets)
+
+Copyright (c) 2015 Rolls-Royce Controls and Data Services Limited.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Rolls-Royce Controls and Data Services Limited nor
+ the names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(43) - FTDI (ft32-* targets)
+
+Copyright (C) 2014 FTDI (support@ftdichip.com)
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+(44) - Synopsys Inc (arc*-* targets)
+
+Copyright (c) 2015, Synopsys, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1) Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2) Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3) Neither the name of the Synopsys, Inc., nor the names of its contributors
+may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+(45) embedded brains - RTEMS targets
+
+Copyright (c) 2017 embedded brains GmbH
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(46) John Baldwin - RTEMS targets
+
+Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(47) Jeffrey Roberson - RTEMS targets
+
+Copyright (c) 2008, Jeffrey Roberson <jeff@freebsd.org>
+All rights reserved.
+
+Copyright (c) 2008 Nokia Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice unmodified, this list of conditions, and the following
+ disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(48) - SiFive Inc. (riscv-* targets)
+
+Copyright (c) 2017 SiFive Inc. All rights reserved.
+
+This copyrighted material is made available to anyone wishing to use,
+modify, copy, or redistribute it subject to the terms and conditions
+of the FreeBSD License. This program is distributed in the hope that
+it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
+including the implied warranties of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. A copy of this license is available at
+http://www.opensource.org/licenses.
+
+(49) Michael R. Neilly (riscv-* targets)
+
+(c) Copyright 2017 Michael R. Neilly
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+* Neither the names of the copyright holders nor the names of their
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+(50) Mentor Graphics (amdgcn-* targets)
+
+Copyright (c) 2014-2017 Mentor Graphics.
+
+The authors hereby grant permission to use, copy, modify, distribute,
+and license this software and its documentation for any purpose, provided
+that existing copyright notices are retained in all copies and that this
+notice is included verbatim in any distributions. No written agreement,
+license, or royalty fee is required for any of the authorized uses.
+Modifications to this software may be copyrighted by their authors
+and need not follow the licensing terms described here, provided that
+the new terms are clearly indicated on the first page of each file where
+they apply.
+
+(51) BSD-2-Clause-FreeBSD (pru-* targets)
+
+SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+
+Copyright (c) 2018-2019 Dimitar Dimitrov <dimitar@dinux.eu>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(52) Andrew Turner (arm-* targets)
+
+Copyright (c) 2013 Andrew Turner <andrew@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(53) BSD-2-Clause-FreeBSD David Schultz (arm-* targets)
+
+SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+
+Copyright (c) 2004-2011 David Schultz <das@FreeBSD.ORG>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(54) - C-SKY Microsystems (csky-* targets)
+
+Copyright (c) 2020 C-SKY Microsystems All rights reserved.
+
+This copyrighted material is made available to anyone wishing to use,
+modify, copy, or redistribute it subject to the terms and conditions
+of the FreeBSD License. This program is distributed in the hope that
+it will be useful, but WITHOUT ANY WARRANTY expressed or implied,
+including the implied warranties of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE. A copy of this license is available at
+http://www.opensource.org/licenses.
+
+(55) BSD-3-Clause-FreeBSD Peter Wemm (rtems targets)
+
+SPDX-License-Identifier: BSD-3-Clause
+
+Copyright (c) 1997 Peter Wemm <peter@freebsd.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+(56) MIT OR Apache-2.0 WITH LLVM-exception (newlib/libc/machine/aarch64)
+
+SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
+
+
+MIT License
+-----------
+
+Copyright (c) 1999-2023, Arm Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+Apache-2.0 WITH LLVM-exception
+------------------------------
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+--- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
+(57) Steven G. Kargl - libm ld128 functions
+
+/*-
+ * Copyright (c) 2017-2023 Steven G. Kargl
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
diff --git a/src/libc/include/ctype.h b/src/libc/include/ctype.h
new file mode 100644
index 0000000..861da65
--- /dev/null
+++ b/src/libc/include/ctype.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+int isalpha(int __c);
+int islower(int __c);
+int isspace(int __c);
+int isupper(int __c);
+int tolower(int __c);
+int toupper(int __c);
+
+#endif
diff --git a/src/libc/include/errno.h b/src/libc/include/errno.h
index 0456645..3646089 100644
--- a/src/libc/include/errno.h
+++ b/src/libc/include/errno.h
@@ -1,3 +1,38 @@
+/* Copyright (C) 1991-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#ifndef _ERRNO_H
#define _ERRNO_H
@@ -5,7 +40,7 @@ extern int errno;
enum
{
- OK,
+ SUCCESS,
EPERM,
ENOENT,
ESRCH,
@@ -38,6 +73,105 @@ enum
EROFS,
EMLINK,
EPIPE,
+ EDOM,
+ ERANGE,
+ EDEADLK,
+ ENAMETOOLONG,
+ ENOLCK,
+ ENOSYS,
+ ENOTEMPTY,
+ ELOOP,
+ ENOMSG,
+ EIDRM,
+ ECHRNG,
+ EL2NSYNC,
+ EL3HLT,
+ EL3RST,
+ ELNRNG,
+ EUNATCH,
+ ENOCSI,
+ EL2HLT,
+ EBADE,
+ EBADR,
+ EXFULL,
+ ENOANO,
+ EBADRQC,
+ EBADSLT,
+ EBFONT,
+ ENOSTR,
+ ENODATA,
+ ETIME,
+ ENOSR,
+ ENONET,
+ ENOPKG,
+ EREMOTE,
+ ENOLINK,
+ EADV,
+ ESRMNT,
+ ECOMM,
+ EPROTO,
+ EMULTIHOP,
+ EDOTDOT,
+ EBADMSG,
+ EOVERFLOW,
+ ENOTUNIQ,
+ EBADFD,
+ EREMCHG,
+ ELIBACC,
+ ELIBBAD,
+ ELIBSCN,
+ ELIBMAX,
+ ELIBEXEC,
+ EILSEQ,
+ ERESTART,
+ ESTRPIPE,
+ EUSERS,
+ ENOTSOCK,
+ EDESTADDRREQ,
+ EMSGSIZE,
+ EPROTOTYPE,
+ ENOPROTOOPT,
+ EPROTONOSUPPORT,
+ ESOCKTNOSUPPORT,
+ ENOTSUP,
+ EPFNOSUPPORT,
+ EAFNOSUPPORT,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ ENETDOWN,
+ ENETUNREACH,
+ ENETRESET,
+ ECONNABORTED,
+ ECONNRESET,
+ ENOBUFS,
+ EISCONN,
+ ENOTCONN,
+ ESHUTDOWN,
+ ETOOMANYREFS,
+ ETIMEDOUT,
+ ECONNREFUSED,
+ EHOSTDOWN,
+ EHOSTUNREACH,
+ EALREADY,
+ EINPROGRESS,
+ ESTALE,
+ EUCLEAN,
+ ENOTNAM,
+ ENAVAIL,
+ EISNAM,
+ EREMOTEIO,
+ EDQUOT,
+ ENOMEDIUM,
+ EMEDIUMTYPE,
+ ECANCELED,
+ ENOKEY,
+ EKEYEXPIRED,
+ EKEYREVOKED,
+ EKEYREJECTED,
+ EOWNERDEAD,
+ ENOTRECOVERABLE,
+ ERFKILL,
+ EHWPOISON
};
#endif
diff --git a/src/libc/include/fcntl.h b/src/libc/include/fcntl.h
new file mode 100644
index 0000000..282ced8
--- /dev/null
+++ b/src/libc/include/fcntl.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+enum
+{
+ O_RDONLY = 1,
+ O_WRONLY = 1 << 1,
+ O_RDWR = O_RDONLY | O_WRONLY
+};
+
+#endif
diff --git a/src/libc/include/inttypes.h b/src/libc/include/inttypes.h
new file mode 100644
index 0000000..afb424c
--- /dev/null
+++ b/src/libc/include/inttypes.h
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#define PRIu8 "hhu"
+#define PRIu16 "hu"
+#define PRIu32 "lu"
+#define PRIu64 "llu"
+#define PRIi8 "hhd"
+#define PRIi16 "hd"
+#define PRIi32 "ld"
+#define PRIi64 "lld"
+#define PRIx8 "hhx"
+#define PRIx16 "hx"
+#define PRIx32 "lx"
+#define PRIx64 "llx"
+
+#endif
diff --git a/src/libc/include/limits.h b/src/libc/include/limits.h
new file mode 100644
index 0000000..6c50848
--- /dev/null
+++ b/src/libc/include/limits.h
@@ -0,0 +1,152 @@
+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef _LIMITS_H___
+#define _LIMITS_H___
+
+/* Number of bits in a `char'. */
+#undef CHAR_BIT
+#define CHAR_BIT __CHAR_BIT__
+
+/* Maximum length of a multibyte character. */
+#ifndef MB_LEN_MAX
+#define MB_LEN_MAX 1
+#endif
+
+/* Minimum and maximum values a `signed char' can hold. */
+#undef SCHAR_MIN
+#define SCHAR_MIN (-SCHAR_MAX - 1)
+#undef SCHAR_MAX
+#define SCHAR_MAX __SCHAR_MAX__
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0). */
+#undef UCHAR_MAX
+#if __SCHAR_MAX__ == __INT_MAX__
+# define UCHAR_MAX (SCHAR_MAX * 2U + 1U)
+#else
+# define UCHAR_MAX (SCHAR_MAX * 2 + 1)
+#endif
+
+/* Minimum and maximum values a `char' can hold. */
+#ifdef __CHAR_UNSIGNED__
+# undef CHAR_MIN
+# if __SCHAR_MAX__ == __INT_MAX__
+# define CHAR_MIN 0U
+# else
+# define CHAR_MIN 0
+# endif
+# undef CHAR_MAX
+# define CHAR_MAX UCHAR_MAX
+#else
+# undef CHAR_MIN
+# define CHAR_MIN SCHAR_MIN
+# undef CHAR_MAX
+# define CHAR_MAX SCHAR_MAX
+#endif
+
+/* Minimum and maximum values a `signed short int' can hold. */
+#undef SHRT_MIN
+#define SHRT_MIN (-SHRT_MAX - 1)
+#undef SHRT_MAX
+#define SHRT_MAX __SHRT_MAX__
+
+/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */
+#undef USHRT_MAX
+#if __SHRT_MAX__ == __INT_MAX__
+# define USHRT_MAX (SHRT_MAX * 2U + 1U)
+#else
+# define USHRT_MAX (SHRT_MAX * 2 + 1)
+#endif
+
+/* Minimum and maximum values a `signed int' can hold. */
+#undef INT_MIN
+#define INT_MIN (-INT_MAX - 1)
+#undef INT_MAX
+#define INT_MAX __INT_MAX__
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0). */
+#undef UINT_MAX
+#define UINT_MAX (INT_MAX * 2U + 1U)
+
+/* Minimum and maximum values a `signed long int' can hold.
+ (Same as `int'). */
+#undef LONG_MIN
+#define LONG_MIN (-LONG_MAX - 1L)
+#undef LONG_MAX
+#define LONG_MAX __LONG_MAX__
+
+/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */
+#undef ULONG_MAX
+#define ULONG_MAX (LONG_MAX * 2UL + 1UL)
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+/* Minimum and maximum values a `signed long long int' can hold. */
+# undef LLONG_MIN
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+# undef LLONG_MAX
+# define LLONG_MAX __LONG_LONG_MAX__
+
+/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */
+# undef ULLONG_MAX
+# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
+#endif
+
+#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__)
+/* Minimum and maximum values a `signed long long int' can hold. */
+# undef LONG_LONG_MIN
+# define LONG_LONG_MIN (-LONG_LONG_MAX - 1LL)
+# undef LONG_LONG_MAX
+# define LONG_LONG_MAX __LONG_LONG_MAX__
+
+/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */
+# undef ULONG_LONG_MAX
+# define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL)
+#endif
+
+#ifdef __STDC_WANT_IEC_60559_BFP_EXT__
+/* TS 18661-1 widths of integer types. */
+# undef CHAR_WIDTH
+# define CHAR_WIDTH __SCHAR_WIDTH__
+# undef SCHAR_WIDTH
+# define SCHAR_WIDTH __SCHAR_WIDTH__
+# undef UCHAR_WIDTH
+# define UCHAR_WIDTH __SCHAR_WIDTH__
+# undef SHRT_WIDTH
+# define SHRT_WIDTH __SHRT_WIDTH__
+# undef USHRT_WIDTH
+# define USHRT_WIDTH __SHRT_WIDTH__
+# undef INT_WIDTH
+# define INT_WIDTH __INT_WIDTH__
+# undef UINT_WIDTH
+# define UINT_WIDTH __INT_WIDTH__
+# undef LONG_WIDTH
+# define LONG_WIDTH __LONG_WIDTH__
+# undef ULONG_WIDTH
+# define ULONG_WIDTH __LONG_WIDTH__
+# undef LLONG_WIDTH
+# define LLONG_WIDTH __LONG_LONG_WIDTH__
+# undef ULLONG_WIDTH
+# define ULLONG_WIDTH __LONG_LONG_WIDTH__
+#endif
+
+#endif /* _LIMITS_H___ */
diff --git a/src/libc/include/setjmp.h b/src/libc/include/setjmp.h
new file mode 100644
index 0000000..d372c91
--- /dev/null
+++ b/src/libc/include/setjmp.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _STDJUMP_H
+#define _STDJUMP_H
+
+typedef struct
+{
+ unsigned pc, sp, fp, s0, s1, s2, s3, s4, s5, s6, s7, gp;
+} jmp_buf[1];
+
+int setjmp(jmp_buf __env);
+
+#endif
diff --git a/src/libc/include/stdarg.h b/src/libc/include/stdarg.h
new file mode 100644
index 0000000..eeb4d3f
--- /dev/null
+++ b/src/libc/include/stdarg.h
@@ -0,0 +1,127 @@
+/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+/*
+ * ISO C Standard: 7.15 Variable arguments <stdarg.h>
+ */
+
+#ifndef _STDARG_H
+#ifndef _ANSI_STDARG_H_
+#ifndef __need___va_list
+#define _STDARG_H
+#define _ANSI_STDARG_H_
+#endif /* not __need___va_list */
+#undef __need___va_list
+
+/* Define __gnuc_va_list. */
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+typedef __builtin_va_list __gnuc_va_list;
+#endif
+
+/* Define the standard macros for the user,
+ if this invocation was from the user program. */
+#ifdef _STDARG_H
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L \
+ || __cplusplus + 0 >= 201103L
+#define va_copy(d,s) __builtin_va_copy(d,s)
+#endif
+#define __va_copy(d,s) __builtin_va_copy(d,s)
+
+/* Define va_list, if desired, from __gnuc_va_list. */
+/* We deliberately do not define va_list when called from
+ stdio.h, because ANSI C says that stdio.h is not supposed to define
+ va_list. stdio.h needs to have access to that data type,
+ but must not use that name. It should use the name __gnuc_va_list,
+ which is safe because it is reserved for the implementation. */
+
+#ifdef _BSD_VA_LIST
+#undef _BSD_VA_LIST
+#endif
+
+#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST))
+/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
+ so we must avoid testing it and setting it here.
+ SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
+ have no conflict with that. */
+#ifndef _VA_LIST_
+#define _VA_LIST_
+#ifdef __i860__
+#ifndef _VA_LIST
+#define _VA_LIST va_list
+#endif
+#endif /* __i860__ */
+typedef __gnuc_va_list va_list;
+#ifdef _SCO_DS
+#define __VA_LIST
+#endif
+#endif /* _VA_LIST_ */
+#else /* not __svr4__ || _SCO_DS */
+
+/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
+ But on BSD NET2 we must not test or define or undef it.
+ (Note that the comments in NET 2's ansi.h
+ are incorrect for _VA_LIST_--see stdio.h!) */
+#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT)
+/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */
+#ifndef _VA_LIST_DEFINED
+/* The macro _VA_LIST is used in SCO Unix 3.2. */
+#ifndef _VA_LIST
+/* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+#ifndef _VA_LIST_T_H
+/* The macro __va_list__ is used by BeOS. */
+#ifndef __va_list__
+typedef __gnuc_va_list va_list;
+#endif /* not __va_list__ */
+#endif /* not _VA_LIST_T_H */
+#endif /* not _VA_LIST */
+#endif /* not _VA_LIST_DEFINED */
+#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
+#define _VA_LIST_
+#endif
+#ifndef _VA_LIST
+#define _VA_LIST
+#endif
+#ifndef _VA_LIST_DEFINED
+#define _VA_LIST_DEFINED
+#endif
+#ifndef _VA_LIST_T_H
+#define _VA_LIST_T_H
+#endif
+#ifndef __va_list__
+#define __va_list__
+#endif
+
+#endif /* not _VA_LIST_, except on certain systems */
+
+#endif /* not __svr4__ */
+
+#endif /* _STDARG_H */
+
+#endif /* not _ANSI_STDARG_H_ */
+#endif /* not _STDARG_H */
diff --git a/src/libc/include/stdbool.h b/src/libc/include/stdbool.h
new file mode 100644
index 0000000..aa55406
--- /dev/null
+++ b/src/libc/include/stdbool.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 1998-2018 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+/*
+ * ISO C Standard: 7.16 Boolean type and values <stdbool.h>
+ */
+
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+#ifndef __cplusplus
+
+#define bool _Bool
+#define true 1
+#define false 0
+
+#else /* __cplusplus */
+
+/* Supporting _Bool in C++ is a GCC extension. */
+#define _Bool bool
+
+#if __cplusplus < 201103L
+/* Defining these macros in C++98 is a GCC extension. */
+#define bool bool
+#define false false
+#define true true
+#endif
+
+#endif /* __cplusplus */
+
+/* Signal that all the definitions are present. */
+#define __bool_true_false_are_defined 1
+
+#endif /* stdbool.h */
diff --git a/src/libc/include/stddef.h b/src/libc/include/stddef.h
new file mode 100644
index 0000000..31b96a7
--- /dev/null
+++ b/src/libc/include/stddef.h
@@ -0,0 +1,451 @@
+/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+/*
+ * ISO C Standard: 7.17 Common definitions <stddef.h>
+ */
+#if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
+ && !defined(__STDDEF_H__)) \
+ || defined(__need_wchar_t) || defined(__need_size_t) \
+ || defined(__need_ptrdiff_t) || defined(__need_NULL) \
+ || defined(__need_wint_t)
+
+/* Any one of these symbols __need_* means that GNU libc
+ wants us just to define one data type. So don't define
+ the symbols that indicate this file's entire job has been done. */
+#if (!defined(__need_wchar_t) && !defined(__need_size_t) \
+ && !defined(__need_ptrdiff_t) && !defined(__need_NULL) \
+ && !defined(__need_wint_t))
+#define _STDDEF_H
+#define _STDDEF_H_
+/* snaroff@next.com says the NeXT needs this. */
+#define _ANSI_STDDEF_H
+#endif
+
+#ifndef __sys_stdtypes_h
+/* This avoids lossage on SunOS but only if stdtypes.h comes first.
+ There's no way to win with the other order! Sun lossage. */
+
+/* On 4.3bsd-net2, make sure ansi.h is included, so we have
+ one less case to deal with in the following. */
+#if defined (__BSD_NET2__) || defined (____386BSD____) || (defined (__FreeBSD__) && (__FreeBSD__ < 5)) || defined(__NetBSD__)
+#include <machine/ansi.h>
+#endif
+/* On FreeBSD 5, machine/ansi.h does not exist anymore... */
+#if defined (__FreeBSD__) && (__FreeBSD__ >= 5)
+#include <sys/_types.h>
+#endif
+
+/* In 4.3bsd-net2, machine/ansi.h defines these symbols, which are
+ defined if the corresponding type is *not* defined.
+ FreeBSD-2.1 defines _MACHINE_ANSI_H_ instead of _ANSI_H_.
+ NetBSD defines _I386_ANSI_H_ and _X86_64_ANSI_H_ instead of _ANSI_H_ */
+#if defined(_ANSI_H_) || defined(_MACHINE_ANSI_H_) || defined(_X86_64_ANSI_H_) || defined(_I386_ANSI_H_)
+#if !defined(_SIZE_T_) && !defined(_BSD_SIZE_T_)
+#define _SIZE_T
+#endif
+#if !defined(_PTRDIFF_T_) && !defined(_BSD_PTRDIFF_T_)
+#define _PTRDIFF_T
+#endif
+/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_
+ instead of _WCHAR_T_. */
+#if !defined(_WCHAR_T_) && !defined(_BSD_WCHAR_T_)
+#ifndef _BSD_WCHAR_T_
+#define _WCHAR_T
+#endif
+#endif
+/* Undef _FOO_T_ if we are supposed to define foo_t. */
+#if defined (__need_ptrdiff_t) || defined (_STDDEF_H_)
+#undef _PTRDIFF_T_
+#undef _BSD_PTRDIFF_T_
+#endif
+#if defined (__need_size_t) || defined (_STDDEF_H_)
+#undef _SIZE_T_
+#undef _BSD_SIZE_T_
+#endif
+#if defined (__need_wchar_t) || defined (_STDDEF_H_)
+#undef _WCHAR_T_
+#undef _BSD_WCHAR_T_
+#endif
+#endif /* defined(_ANSI_H_) || defined(_MACHINE_ANSI_H_) || defined(_X86_64_ANSI_H_) || defined(_I386_ANSI_H_) */
+
+/* Sequent's header files use _PTRDIFF_T_ in some conflicting way.
+ Just ignore it. */
+#if defined (__sequent__) && defined (_PTRDIFF_T_)
+#undef _PTRDIFF_T_
+#endif
+
+/* On VxWorks, <type/vxTypesBase.h> may have defined macros like
+ _TYPE_size_t which will typedef size_t. fixincludes patched the
+ vxTypesBase.h so that this macro is only defined if _GCC_SIZE_T is
+ not defined, and so that defining this macro defines _GCC_SIZE_T.
+ If we find that the macros are still defined at this point, we must
+ invoke them so that the type is defined as expected. */
+#if defined (_TYPE_ptrdiff_t) && (defined (__need_ptrdiff_t) || defined (_STDDEF_H_))
+_TYPE_ptrdiff_t;
+#undef _TYPE_ptrdiff_t
+#endif
+#if defined (_TYPE_size_t) && (defined (__need_size_t) || defined (_STDDEF_H_))
+_TYPE_size_t;
+#undef _TYPE_size_t
+#endif
+#if defined (_TYPE_wchar_t) && (defined (__need_wchar_t) || defined (_STDDEF_H_))
+_TYPE_wchar_t;
+#undef _TYPE_wchar_t
+#endif
+
+/* In case nobody has defined these types, but we aren't running under
+ GCC 2.00, make sure that __PTRDIFF_TYPE__, __SIZE_TYPE__, and
+ __WCHAR_TYPE__ have reasonable values. This can happen if the
+ parts of GCC is compiled by an older compiler, that actually
+ include gstddef.h, such as collect2. */
+
+/* Signed type of difference of two pointers. */
+
+/* Define this type if we are doing the whole job,
+ or if we want this type in particular. */
+#if defined (_STDDEF_H) || defined (__need_ptrdiff_t)
+#ifndef _PTRDIFF_T /* in case <sys/types.h> has defined it. */
+#ifndef _T_PTRDIFF_
+#ifndef _T_PTRDIFF
+#ifndef __PTRDIFF_T
+#ifndef _PTRDIFF_T_
+#ifndef _BSD_PTRDIFF_T_
+#ifndef ___int_ptrdiff_t_h
+#ifndef _GCC_PTRDIFF_T
+#ifndef _PTRDIFF_T_DECLARED /* DragonFly */
+#define _PTRDIFF_T
+#define _T_PTRDIFF_
+#define _T_PTRDIFF
+#define __PTRDIFF_T
+#define _PTRDIFF_T_
+#define _BSD_PTRDIFF_T_
+#define ___int_ptrdiff_t_h
+#define _GCC_PTRDIFF_T
+#define _PTRDIFF_T_DECLARED
+#ifndef __PTRDIFF_TYPE__
+#define __PTRDIFF_TYPE__ long int
+#endif
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#endif /* _PTRDIFF_T_DECLARED */
+#endif /* _GCC_PTRDIFF_T */
+#endif /* ___int_ptrdiff_t_h */
+#endif /* _BSD_PTRDIFF_T_ */
+#endif /* _PTRDIFF_T_ */
+#endif /* __PTRDIFF_T */
+#endif /* _T_PTRDIFF */
+#endif /* _T_PTRDIFF_ */
+#endif /* _PTRDIFF_T */
+
+/* If this symbol has done its job, get rid of it. */
+#undef __need_ptrdiff_t
+
+#endif /* _STDDEF_H or __need_ptrdiff_t. */
+
+/* Unsigned type of `sizeof' something. */
+
+/* Define this type if we are doing the whole job,
+ or if we want this type in particular. */
+#if defined (_STDDEF_H) || defined (__need_size_t)
+#ifndef __size_t__ /* BeOS */
+#ifndef __SIZE_T__ /* Cray Unicos/Mk */
+#ifndef _SIZE_T /* in case <sys/types.h> has defined it. */
+#ifndef _SYS_SIZE_T_H
+#ifndef _T_SIZE_
+#ifndef _T_SIZE
+#ifndef __SIZE_T
+#ifndef _SIZE_T_
+#ifndef _BSD_SIZE_T_
+#ifndef _SIZE_T_DEFINED_
+#ifndef _SIZE_T_DEFINED
+#ifndef _BSD_SIZE_T_DEFINED_ /* Darwin */
+#ifndef _SIZE_T_DECLARED /* FreeBSD 5 */
+#ifndef ___int_size_t_h
+#ifndef _GCC_SIZE_T
+#ifndef _SIZET_
+#ifndef __size_t
+#define __size_t__ /* BeOS */
+#define __SIZE_T__ /* Cray Unicos/Mk */
+#define _SIZE_T
+#define _SYS_SIZE_T_H
+#define _T_SIZE_
+#define _T_SIZE
+#define __SIZE_T
+#define _SIZE_T_
+#define _BSD_SIZE_T_
+#define _SIZE_T_DEFINED_
+#define _SIZE_T_DEFINED
+#define _BSD_SIZE_T_DEFINED_ /* Darwin */
+#define _SIZE_T_DECLARED /* FreeBSD 5 */
+#define ___int_size_t_h
+#define _GCC_SIZE_T
+#define _SIZET_
+#if (defined (__FreeBSD__) && (__FreeBSD__ >= 5)) \
+ || defined(__DragonFly__) \
+ || defined(__FreeBSD_kernel__)
+/* __size_t is a typedef on FreeBSD 5, must not trash it. */
+#elif defined (__VMS__)
+/* __size_t is also a typedef on VMS. */
+#else
+#define __size_t
+#endif
+#ifndef __SIZE_TYPE__
+#define __SIZE_TYPE__ long unsigned int
+#endif
+#if !(defined (__GNUG__) && defined (size_t))
+typedef __SIZE_TYPE__ size_t;
+#ifdef __BEOS__
+typedef long ssize_t;
+#endif /* __BEOS__ */
+#endif /* !(defined (__GNUG__) && defined (size_t)) */
+#endif /* __size_t */
+#endif /* _SIZET_ */
+#endif /* _GCC_SIZE_T */
+#endif /* ___int_size_t_h */
+#endif /* _SIZE_T_DECLARED */
+#endif /* _BSD_SIZE_T_DEFINED_ */
+#endif /* _SIZE_T_DEFINED */
+#endif /* _SIZE_T_DEFINED_ */
+#endif /* _BSD_SIZE_T_ */
+#endif /* _SIZE_T_ */
+#endif /* __SIZE_T */
+#endif /* _T_SIZE */
+#endif /* _T_SIZE_ */
+#endif /* _SYS_SIZE_T_H */
+#endif /* _SIZE_T */
+#endif /* __SIZE_T__ */
+#endif /* __size_t__ */
+#undef __need_size_t
+#endif /* _STDDEF_H or __need_size_t. */
+
+
+/* Wide character type.
+ Locale-writers should change this as necessary to
+ be big enough to hold unique values not between 0 and 127,
+ and not (wchar_t) -1, for each defined multibyte character. */
+
+/* Define this type if we are doing the whole job,
+ or if we want this type in particular. */
+#if defined (_STDDEF_H) || defined (__need_wchar_t)
+#ifndef __wchar_t__ /* BeOS */
+#ifndef __WCHAR_T__ /* Cray Unicos/Mk */
+#ifndef _WCHAR_T
+#ifndef _T_WCHAR_
+#ifndef _T_WCHAR
+#ifndef __WCHAR_T
+#ifndef _WCHAR_T_
+#ifndef _BSD_WCHAR_T_
+#ifndef _BSD_WCHAR_T_DEFINED_ /* Darwin */
+#ifndef _BSD_RUNE_T_DEFINED_ /* Darwin */
+#ifndef _WCHAR_T_DECLARED /* FreeBSD 5 */
+#ifndef _WCHAR_T_DEFINED_
+#ifndef _WCHAR_T_DEFINED
+#ifndef _WCHAR_T_H
+#ifndef ___int_wchar_t_h
+#ifndef __INT_WCHAR_T_H
+#ifndef _GCC_WCHAR_T
+#define __wchar_t__ /* BeOS */
+#define __WCHAR_T__ /* Cray Unicos/Mk */
+#define _WCHAR_T
+#define _T_WCHAR_
+#define _T_WCHAR
+#define __WCHAR_T
+#define _WCHAR_T_
+#define _BSD_WCHAR_T_
+#define _WCHAR_T_DEFINED_
+#define _WCHAR_T_DEFINED
+#define _WCHAR_T_H
+#define ___int_wchar_t_h
+#define __INT_WCHAR_T_H
+#define _GCC_WCHAR_T
+#define _WCHAR_T_DECLARED
+
+/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_
+ instead of _WCHAR_T_, and _BSD_RUNE_T_ (which, unlike the other
+ symbols in the _FOO_T_ family, stays defined even after its
+ corresponding type is defined). If we define wchar_t, then we
+ must undef _WCHAR_T_; for BSD/386 1.1 (and perhaps others), if
+ we undef _WCHAR_T_, then we must also define rune_t, since
+ headers like runetype.h assume that if machine/ansi.h is included,
+ and _BSD_WCHAR_T_ is not defined, then rune_t is available.
+ machine/ansi.h says, "Note that _WCHAR_T_ and _RUNE_T_ must be of
+ the same type." */
+#ifdef _BSD_WCHAR_T_
+#undef _BSD_WCHAR_T_
+#ifdef _BSD_RUNE_T_
+#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE)
+typedef _BSD_RUNE_T_ rune_t;
+#define _BSD_WCHAR_T_DEFINED_
+#define _BSD_RUNE_T_DEFINED_ /* Darwin */
+#if defined (__FreeBSD__) && (__FreeBSD__ < 5)
+/* Why is this file so hard to maintain properly? In contrast to
+ the comment above regarding BSD/386 1.1, on FreeBSD for as long
+ as the symbol has existed, _BSD_RUNE_T_ must not stay defined or
+ redundant typedefs will occur when stdlib.h is included after this file. */
+#undef _BSD_RUNE_T_
+#endif
+#endif
+#endif
+#endif
+/* FreeBSD 5 can't be handled well using "traditional" logic above
+ since it no longer defines _BSD_RUNE_T_ yet still desires to export
+ rune_t in some cases... */
+#if defined (__FreeBSD__) && (__FreeBSD__ >= 5)
+#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE)
+#if __BSD_VISIBLE
+#ifndef _RUNE_T_DECLARED
+typedef __rune_t rune_t;
+#define _RUNE_T_DECLARED
+#endif
+#endif
+#endif
+#endif
+
+#ifndef __WCHAR_TYPE__
+#define __WCHAR_TYPE__ int
+#endif
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif /* _WCHAR_T_DECLARED */
+#endif /* _BSD_RUNE_T_DEFINED_ */
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif /* __WCHAR_T__ */
+#endif /* __wchar_t__ */
+#undef __need_wchar_t
+#endif /* _STDDEF_H or __need_wchar_t. */
+
+#if defined (__need_wint_t)
+#ifndef _WINT_T
+#define _WINT_T
+
+#ifndef __WINT_TYPE__
+#define __WINT_TYPE__ unsigned int
+#endif
+typedef __WINT_TYPE__ wint_t;
+#endif
+#undef __need_wint_t
+#endif
+
+/* In 4.3bsd-net2, leave these undefined to indicate that size_t, etc.
+ are already defined. */
+/* BSD/OS 3.1 and FreeBSD [23].x require the MACHINE_ANSI_H check here. */
+/* NetBSD 5 requires the I386_ANSI_H and X86_64_ANSI_H checks here. */
+#if defined(_ANSI_H_) || defined(_MACHINE_ANSI_H_) || defined(_X86_64_ANSI_H_) || defined(_I386_ANSI_H_)
+/* The references to _GCC_PTRDIFF_T_, _GCC_SIZE_T_, and _GCC_WCHAR_T_
+ are probably typos and should be removed before 2.8 is released. */
+#ifdef _GCC_PTRDIFF_T_
+#undef _PTRDIFF_T_
+#undef _BSD_PTRDIFF_T_
+#endif
+#ifdef _GCC_SIZE_T_
+#undef _SIZE_T_
+#undef _BSD_SIZE_T_
+#endif
+#ifdef _GCC_WCHAR_T_
+#undef _WCHAR_T_
+#undef _BSD_WCHAR_T_
+#endif
+/* The following ones are the real ones. */
+#ifdef _GCC_PTRDIFF_T
+#undef _PTRDIFF_T_
+#undef _BSD_PTRDIFF_T_
+#endif
+#ifdef _GCC_SIZE_T
+#undef _SIZE_T_
+#undef _BSD_SIZE_T_
+#endif
+#ifdef _GCC_WCHAR_T
+#undef _WCHAR_T_
+#undef _BSD_WCHAR_T_
+#endif
+#endif /* _ANSI_H_ || _MACHINE_ANSI_H_ || _X86_64_ANSI_H_ || _I386_ANSI_H_ */
+
+#endif /* __sys_stdtypes_h */
+
+/* A null pointer constant. */
+
+#if defined (_STDDEF_H) || defined (__need_NULL)
+#undef NULL /* in case <stdio.h> has defined it. */
+#ifdef __GNUG__
+#define NULL __null
+#else /* G++ */
+#ifndef __cplusplus
+#define NULL ((void *)0)
+#else /* C++ */
+#define NULL 0
+#endif /* C++ */
+#endif /* G++ */
+#endif /* NULL not defined and <stddef.h> or need NULL. */
+#undef __need_NULL
+
+#ifdef _STDDEF_H
+
+/* Offset of member MEMBER in a struct of type TYPE. */
+#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
+
+#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
+ || (defined(__cplusplus) && __cplusplus >= 201103L)
+#ifndef _GCC_MAX_ALIGN_T
+#define _GCC_MAX_ALIGN_T
+/* Type whose alignment is supported in every context and is at least
+ as great as that of any standard type not using alignment
+ specifiers. */
+typedef struct {
+ long long __max_align_ll __attribute__((__aligned__(__alignof__(long long))));
+ long double __max_align_ld __attribute__((__aligned__(__alignof__(long double))));
+ /* _Float128 is defined as a basic type, so max_align_t must be
+ sufficiently aligned for it. This code must work in C++, so we
+ use __float128 here; that is only available on some
+ architectures, but only on i386 is extra alignment needed for
+ __float128. */
+#ifdef __i386__
+ __float128 __max_align_f128 __attribute__((__aligned__(__alignof(__float128))));
+#endif
+} max_align_t;
+#endif
+#endif /* C11 or C++11. */
+
+#if defined(__cplusplus) && __cplusplus >= 201103L
+#ifndef _GXX_NULLPTR_T
+#define _GXX_NULLPTR_T
+ typedef decltype(nullptr) nullptr_t;
+#endif
+#endif /* C++11. */
+
+#endif /* _STDDEF_H was defined this time */
+
+#endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__
+ || __need_XXX was not defined before */
diff --git a/src/libc/include/stdint.h b/src/libc/include/stdint.h
new file mode 100644
index 0000000..ba8419a
--- /dev/null
+++ b/src/libc/include/stdint.h
@@ -0,0 +1,33 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+typedef unsigned char uint8_t, uint_least8_t;
+typedef signed char int8_t, int_least8_t;
+typedef unsigned short uint16_t, uint_least16_t;
+typedef short int16_t, int_least16_t;
+typedef unsigned uintptr_t, uint32_t, uint_least32_t, uint_fast8_t,
+ uint_fast16_t, uint_fast32_t;
+typedef int intptr_t, int32_t, int_least32_t, int_fast8_t, int_fast16_t,
+ int_fast32_t;
+typedef unsigned long long uint64_t, uint_least64_t, uint_fast64_t, uintmax_t;
+typedef long long int64_t, int_least64_t, int_fast64_t, intmax_t;
+
+#endif
diff --git a/src/libc/include/stdio.h b/src/libc/include/stdio.h
index 1d0e27c..b9c1a38 100644
--- a/src/libc/include/stdio.h
+++ b/src/libc/include/stdio.h
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -19,17 +19,11 @@
#ifndef _STDIO_H
#define _STDIO_H
-enum
-{
- EOF = -1
-};
+enum {EOF = -1};
-typedef struct __file FILE;
+int puts(const char *__s);
+int putchar(int __c);
-FILE *fopen(const char *__path, const char *__mode);
-int printf(const char *__fmt, ...);
-int fprintf(FILE *__stream, const char *__fmt, ...);
-
-extern FILE *stdin, *stdout, *stderr;
+#include <printf.h>
#endif
diff --git a/src/libc/include/stdlib.h b/src/libc/include/stdlib.h
index 4065f1c..8f97ea3 100644
--- a/src/libc/include/stdlib.h
+++ b/src/libc/include/stdlib.h
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -24,8 +24,25 @@
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
+#define abort() __abort(__FILE__, __LINE__)
+
+typedef struct
+{
+ int quot, rem;
+} div_t;
+
+int abs(int __v);
+long labs(long __v);
+long long llabs(long long __v);
void *malloc(size_t __n);
void *calloc(size_t __nemb, size_t __size);
+void *realloc(void *__ptr, size_t __size);
void free(void *__p);
+long strtol(const char *__s, char **__end, int __base);
+long long strtoll(const char *__s, char **__end, int __base);
+unsigned long strtoul(const char *__s, char **__end, int __base);
+unsigned long long strtoull(const char *__s, char **__end, int __base);
+void __abort(const char *__file, int __lineno);
+div_t div(int __numerator, int __denominator);
#endif
diff --git a/src/libc/include/string.h b/src/libc/include/string.h
index 20c9cf3..1e62a84 100644
--- a/src/libc/include/string.h
+++ b/src/libc/include/string.h
@@ -1,3 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#ifndef _STRING_H
#define _STRING_H
@@ -6,8 +24,17 @@
int memcmp(const void *__s1, const void *__s2, size_t __n);
void *memcpy(void *__dst, const void *__src, size_t __n);
void *memset(void *__dst, int __c, size_t __n);
+int strcasecmp(const char *__a, const char *__b);
char *strchr(const char *__s, int __n);
-char *strerror(int errnum);
+int strcmp(const char *__a, const char *__b);
+char *strdup(const char *__s);
+char *strerror(int __errnum);
+int strncmp(const char *__a, const char *__b, size_t __n);
+char *strndup(const char *__s, size_t __n);
+char *strpbrk(const char *const __s, const char *__accept);
size_t strlen(const char *__s);
+char *strrchr(const char *__s, int __c);
+size_t strspn(const char *__s, const char *__accept);
+size_t strcspn(const char *__s, const char * __reject);
#endif
diff --git a/src/libc/include/sys/mount.h b/src/libc/include/sys/mount.h
new file mode 100644
index 0000000..eae6d63
--- /dev/null
+++ b/src/libc/include/sys/mount.h
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SYS_MOUNT_H
+#define _SYS_MOUNT_H
+
+int mount(const char *__src, const char *__tgt, const char *__type,
+ unsigned long __flags, const void *__args);
+
+#endif
diff --git a/src/libc/include/sys/stat.h b/src/libc/include/sys/stat.h
new file mode 100644
index 0000000..08fcf9a
--- /dev/null
+++ b/src/libc/include/sys/stat.h
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <sys/types.h>
+#include <time.h>
+
+struct stat
+{
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ struct timespec st_atim, st_mtim, st_ctim;
+ blksize_t st_blksize;
+ blkcnt_t st_blocks;
+};
+
+int mkdir(const char *pathname, mode_t flags);
+
+#endif
diff --git a/src/libc/include/sys/types.h b/src/libc/include/sys/types.h
new file mode 100644
index 0000000..86ca604
--- /dev/null
+++ b/src/libc/include/sys/types.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+typedef unsigned dev_t, mode_t, nlink_t, uid_t, gid_t, blksize_t, blkcnt_t;
+typedef unsigned long ino_t, off_t;
+typedef int pid_t;
+
+#endif
diff --git a/src/libc/include/time.h b/src/libc/include/time.h
new file mode 100644
index 0000000..3b78d22
--- /dev/null
+++ b/src/libc/include/time.h
@@ -0,0 +1,46 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TIME_H
+#define _TIME_H
+
+typedef enum
+{
+ CLOCK_REALTIME
+} clockid_t;
+
+typedef long long time_t;
+
+struct timespec
+{
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+struct tm
+{
+ int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday,
+ tm_isdst;
+};
+
+int clock_getres(clockid_t __id, struct timespec *__ts);
+int clock_gettime(clockid_t __id, struct timespec *__ts);
+int clock_settime(clockid_t __id, const struct timespec *__ts);
+time_t mktime(struct tm *__tm);
+
+#endif
diff --git a/src/libc/include/unistd.h b/src/libc/include/unistd.h
new file mode 100644
index 0000000..ec4fc13
--- /dev/null
+++ b/src/libc/include/unistd.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <stdint.h>
+
+void *sbrk(intptr_t increment);
+
+#endif
diff --git a/src/libc/newlib/CMakeLists.txt b/src/libc/newlib/CMakeLists.txt
new file mode 100644
index 0000000..aedf961
--- /dev/null
+++ b/src/libc/newlib/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(src)
+target_include_directories(c PRIVATE private_include)
diff --git a/src/libc/newlib/private_include/sys/_tz_structs.h b/src/libc/newlib/private_include/sys/_tz_structs.h
new file mode 100644
index 0000000..f20aacb
--- /dev/null
+++ b/src/libc/newlib/private_include/sys/_tz_structs.h
@@ -0,0 +1,30 @@
+#ifndef _SYS__TZ_STRUCTS_H_
+#define _SYS__TZ_STRUCTS_H_
+
+#include <time.h>
+
+typedef struct __tzrule_struct
+{
+ char ch;
+ int m; /* Month of year if ch=M */
+ int n; /* Week of month if ch=M */
+ int d; /* Day of week if ch=M, day of year if ch=J or ch=D */
+ int s; /* Time of day in seconds */
+ time_t change;
+ long offset; /* Match type of _timezone. */
+} __tzrule_type;
+
+typedef struct __tzinfo_struct
+{
+ int __tznorth;
+ int __tzyear;
+ __tzrule_type __tzrule[2];
+} __tzinfo_type;
+
+__tzinfo_type *__gettzinfo (void);
+
+extern char *_tzname[2];
+extern int _daylight;
+extern long _timezone;
+
+#endif /* _SYS__TZ_STRUCTS_H_ */
diff --git a/src/libc/newlib/src/CMakeLists.txt b/src/libc/newlib/src/CMakeLists.txt
new file mode 100644
index 0000000..f2f8ba4
--- /dev/null
+++ b/src/libc/newlib/src/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_subdirectory(stdlib)
+add_subdirectory(time)
diff --git a/src/libc/newlib/src/stdlib/CMakeLists.txt b/src/libc/newlib/src/stdlib/CMakeLists.txt
new file mode 100644
index 0000000..ab499b9
--- /dev/null
+++ b/src/libc/newlib/src/stdlib/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ div.c
+)
diff --git a/src/libc/newlib/src/stdlib/div.c b/src/libc/newlib/src/stdlib/div.c
new file mode 100644
index 0000000..2a19cae
--- /dev/null
+++ b/src/libc/newlib/src/stdlib/div.c
@@ -0,0 +1,121 @@
+/*
+FUNCTION
+<<div>>---divide two integers
+
+INDEX
+ div
+
+SYNOPSIS
+ #include <stdlib.h>
+ div_t div(int <[n]>, int <[d]>);
+
+DESCRIPTION
+Divide
+@tex
+$n/d$,
+@end tex
+@ifnottex
+<[n]>/<[d]>,
+@end ifnottex
+returning quotient and remainder as two integers in a structure <<div_t>>.
+
+RETURNS
+The result is represented with the structure
+
+. typedef struct
+. {
+. int quot;
+. int rem;
+. } div_t;
+
+where the <<quot>> field represents the quotient, and <<rem>> the
+remainder. For nonzero <[d]>, if `<<<[r]> = div(<[n]>,<[d]>);>>' then
+<[n]> equals `<<<[r]>.rem + <[d]>*<[r]>.quot>>'.
+
+To divide <<long>> rather than <<int>> values, use the similar
+function <<ldiv>>.
+
+PORTABILITY
+<<div>> is ANSI.
+
+No supporting OS subroutines are required.
+*/
+
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h> /* div_t */
+
+div_t
+div (int num,
+ int denom)
+{
+ div_t r;
+
+ r.quot = num / denom;
+ r.rem = num % denom;
+ /*
+ * The ANSI standard says that |r.quot| <= |n/d|, where
+ * n/d is to be computed in infinite precision. In other
+ * words, we should always truncate the quotient towards
+ * 0, never -infinity or +infinity.
+ *
+ * Machine division and remainer may work either way when
+ * one or both of n or d is negative. If only one is
+ * negative and r.quot has been truncated towards -inf,
+ * r.rem will have the same sign as denom and the opposite
+ * sign of num; if both are negative and r.quot has been
+ * truncated towards -inf, r.rem will be positive (will
+ * have the opposite sign of num). These are considered
+ * `wrong'.
+ *
+ * If both are num and denom are positive, r will always
+ * be positive.
+ *
+ * This all boils down to:
+ * if num >= 0, but r.rem < 0, we got the wrong answer.
+ * In that case, to get the right answer, add 1 to r.quot and
+ * subtract denom from r.rem.
+ * if num < 0, but r.rem > 0, we also have the wrong answer.
+ * In this case, to get the right answer, subtract 1 from r.quot and
+ * add denom to r.rem.
+ */
+ if (num >= 0 && r.rem < 0) {
+ ++r.quot;
+ r.rem -= denom;
+ }
+ else if (num < 0 && r.rem > 0) {
+ --r.quot;
+ r.rem += denom;
+ }
+ return (r);
+}
diff --git a/src/libc/newlib/src/time/CMakeLists.txt b/src/libc/newlib/src/time/CMakeLists.txt
new file mode 100644
index 0000000..ea7167f
--- /dev/null
+++ b/src/libc/newlib/src/time/CMakeLists.txt
@@ -0,0 +1,25 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ gettzinfo.c
+ month_lengths.c
+ mktime.c
+ tzvars.c
+ tzcalc_limits.c
+)
+
+target_compile_definitions(c PRIVATE __SINGLE_THREAD__)
diff --git a/src/libc/newlib/src/time/gettzinfo.c b/src/libc/newlib/src/time/gettzinfo.c
new file mode 100644
index 0000000..c28e72f
--- /dev/null
+++ b/src/libc/newlib/src/time/gettzinfo.c
@@ -0,0 +1,15 @@
+#include <sys/types.h>
+#include "local.h"
+
+/* Shared timezone information for libc/time functions. */
+static __tzinfo_type tzinfo = {1, 0,
+ { {'J', 0, 0, 0, 0, (time_t)0, 0L },
+ {'J', 0, 0, 0, 0, (time_t)0, 0L }
+ }
+};
+
+__tzinfo_type *
+__gettzinfo (void)
+{
+ return &tzinfo;
+}
diff --git a/src/libc/newlib/src/time/local.h b/src/libc/newlib/src/time/local.h
new file mode 100644
index 0000000..41940c0
--- /dev/null
+++ b/src/libc/newlib/src/time/local.h
@@ -0,0 +1,38 @@
+/* local header used by libc/time routines */
+#include <time.h>
+#include <sys/_tz_structs.h>
+
+#define SECSPERMIN 60L
+#define MINSPERHOUR 60L
+#define HOURSPERDAY 24L
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY)
+#define DAYSPERWEEK 7
+#define MONSPERYEAR 12
+
+#define YEAR_BASE 1900
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY 4
+#define EPOCH_YEARS_SINCE_LEAP 2
+#define EPOCH_YEARS_SINCE_CENTURY 70
+#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+int __tzcalc_limits (int __year);
+
+extern const int __month_lengths[2][MONSPERYEAR];
+
+void _tzset_unlocked (void);
+
+/* locks for multi-threading */
+#ifdef __SINGLE_THREAD__
+#define TZ_LOCK
+#define TZ_UNLOCK
+#else
+#define TZ_LOCK __tz_lock()
+#define TZ_UNLOCK __tz_unlock()
+#endif
+
+void __tz_lock (void);
+void __tz_unlock (void);
diff --git a/src/libc/newlib/src/time/mktime.c b/src/libc/newlib/src/time/mktime.c
new file mode 100644
index 0000000..4ca1493
--- /dev/null
+++ b/src/libc/newlib/src/time/mktime.c
@@ -0,0 +1,288 @@
+/*
+ * mktime.c
+ * Original Author: G. Haley
+ *
+ * Converts the broken-down time, expressed as local time, in the structure
+ * pointed to by tim_p into a calendar time value. The original values of the
+ * tm_wday and tm_yday fields of the structure are ignored, and the original
+ * values of the other fields have no restrictions. On successful completion
+ * the fields of the structure are set to represent the specified calendar
+ * time. Returns the specified calendar time. If the calendar time can not be
+ * represented, returns the value (time_t) -1.
+ *
+ * Modifications: Fixed tm_isdst usage - 27 August 2008 Craig Howland.
+ */
+
+/*
+FUNCTION
+<<mktime>>---convert time to arithmetic representation
+
+INDEX
+ mktime
+
+SYNOPSIS
+ #include <time.h>
+ time_t mktime(struct tm *<[timp]>);
+
+DESCRIPTION
+<<mktime>> assumes the time at <[timp]> is a local time, and converts
+its representation from the traditional representation defined by
+<<struct tm>> into a representation suitable for arithmetic.
+
+<<localtime>> is the inverse of <<mktime>>.
+
+RETURNS
+If the contents of the structure at <[timp]> do not form a valid
+calendar time representation, the result is <<-1>>. Otherwise, the
+result is the time, converted to a <<time_t>> value.
+
+PORTABILITY
+ANSI C requires <<mktime>>.
+
+<<mktime>> requires no supporting OS subroutines.
+*/
+
+#include "local.h"
+#include <stdlib.h>
+#include <sys/_tz_structs.h>
+#include <time.h>
+
+#define TZ_LOCK
+#define TZ_UNLOCK
+#define _tzset_unlocked()
+#define YEAR_BASE 1900
+
+#define _SEC_IN_MINUTE 60L
+#define _SEC_IN_HOUR 3600L
+#define _SEC_IN_DAY 86400L
+
+static const int DAYS_IN_MONTH[12] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+#define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x])
+
+static const int _DAYS_BEFORE_MONTH[12] =
+{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+#define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0))
+#define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365)
+
+static void
+validate_structure (struct tm *tim_p)
+{
+ div_t res;
+ int days_in_feb = 28;
+
+ /* calculate time & date to account for out of range values */
+ if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59)
+ {
+ res = div (tim_p->tm_sec, 60);
+ tim_p->tm_min += res.quot;
+ if ((tim_p->tm_sec = res.rem) < 0)
+ {
+ tim_p->tm_sec += 60;
+ --tim_p->tm_min;
+ }
+ }
+
+ if (tim_p->tm_min < 0 || tim_p->tm_min > 59)
+ {
+ res = div (tim_p->tm_min, 60);
+ tim_p->tm_hour += res.quot;
+ if ((tim_p->tm_min = res.rem) < 0)
+ {
+ tim_p->tm_min += 60;
+ --tim_p->tm_hour;
+ }
+ }
+
+ if (tim_p->tm_hour < 0 || tim_p->tm_hour > 23)
+ {
+ res = div (tim_p->tm_hour, 24);
+ tim_p->tm_mday += res.quot;
+ if ((tim_p->tm_hour = res.rem) < 0)
+ {
+ tim_p->tm_hour += 24;
+ --tim_p->tm_mday;
+ }
+ }
+
+ if (tim_p->tm_mon < 0 || tim_p->tm_mon > 11)
+ {
+ res = div (tim_p->tm_mon, 12);
+ tim_p->tm_year += res.quot;
+ if ((tim_p->tm_mon = res.rem) < 0)
+ {
+ tim_p->tm_mon += 12;
+ --tim_p->tm_year;
+ }
+ }
+
+ if (_DAYS_IN_YEAR (tim_p->tm_year) == 366)
+ days_in_feb = 29;
+
+ if (tim_p->tm_mday <= 0)
+ {
+ while (tim_p->tm_mday <= 0)
+ {
+ if (--tim_p->tm_mon == -1)
+ {
+ tim_p->tm_year--;
+ tim_p->tm_mon = 11;
+ days_in_feb =
+ ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
+ 29 : 28);
+ }
+ tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon);
+ }
+ }
+ else
+ {
+ while (tim_p->tm_mday > _DAYS_IN_MONTH (tim_p->tm_mon))
+ {
+ tim_p->tm_mday -= _DAYS_IN_MONTH (tim_p->tm_mon);
+ if (++tim_p->tm_mon == 12)
+ {
+ tim_p->tm_year++;
+ tim_p->tm_mon = 0;
+ days_in_feb =
+ ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
+ 29 : 28);
+ }
+ }
+ }
+}
+
+time_t
+mktime (struct tm *tim_p)
+{
+ time_t tim = 0;
+ long days = 0;
+ int year, isdst=0;
+ __tzinfo_type *tz = __gettzinfo ();
+
+ /* validate structure */
+ validate_structure (tim_p);
+
+ /* compute hours, minutes, seconds */
+ tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) +
+ (tim_p->tm_hour * _SEC_IN_HOUR);
+
+ /* compute days in year */
+ days += tim_p->tm_mday - 1;
+ days += _DAYS_BEFORE_MONTH[tim_p->tm_mon];
+ if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366)
+ days++;
+
+ /* compute day of the year */
+ tim_p->tm_yday = days;
+
+ if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000)
+ return (time_t) -1;
+
+ /* compute days in other years */
+ if ((year = tim_p->tm_year) > 70)
+ {
+ for (year = 70; year < tim_p->tm_year; year++)
+ days += _DAYS_IN_YEAR (year);
+ }
+ else if (year < 70)
+ {
+ for (year = 69; year > tim_p->tm_year; year--)
+ days -= _DAYS_IN_YEAR (year);
+ days -= _DAYS_IN_YEAR (year);
+ }
+
+ /* compute total seconds */
+ tim += (time_t)days * _SEC_IN_DAY;
+
+ TZ_LOCK;
+
+ _tzset_unlocked ();
+
+ if (_daylight)
+ {
+ int tm_isdst;
+ int y = tim_p->tm_year + YEAR_BASE;
+ /* Convert user positive into 1 */
+ tm_isdst = tim_p->tm_isdst > 0 ? 1 : tim_p->tm_isdst;
+ isdst = tm_isdst;
+
+ if (y == tz->__tzyear || __tzcalc_limits (y))
+ {
+ /* calculate start of dst in dst local time and
+ start of std in both std local time and dst local time */
+ time_t startdst_dst = tz->__tzrule[0].change
+ - (time_t) tz->__tzrule[1].offset;
+ time_t startstd_dst = tz->__tzrule[1].change
+ - (time_t) tz->__tzrule[1].offset;
+ time_t startstd_std = tz->__tzrule[1].change
+ - (time_t) tz->__tzrule[0].offset;
+ /* if the time is in the overlap between dst and std local times */
+ if (tim >= startstd_std && tim < startstd_dst)
+ ; /* we let user decide or leave as -1 */
+ else
+ {
+ isdst = (tz->__tznorth
+ ? (tim >= startdst_dst && tim < startstd_std)
+ : (tim >= startdst_dst || tim < startstd_std));
+ /* if user committed and was wrong, perform correction, but not
+ * if the user has given a negative value (which
+ * asks mktime() to determine if DST is in effect or not) */
+ if (tm_isdst >= 0 && (isdst ^ tm_isdst) == 1)
+ {
+ /* we either subtract or add the difference between
+ time zone offsets, depending on which way the user got it
+ wrong. The diff is typically one hour, or 3600 seconds,
+ and should fit in a 16-bit int, even though offset
+ is a long to accomodate 12 hours. */
+ int diff = (int) (tz->__tzrule[0].offset
+ - tz->__tzrule[1].offset);
+ if (!isdst)
+ diff = -diff;
+ tim_p->tm_sec += diff;
+ tim += diff; /* we also need to correct our current time calculation */
+ int mday = tim_p->tm_mday;
+ validate_structure (tim_p);
+ mday = tim_p->tm_mday - mday;
+ /* roll over occurred */
+ if (mday) {
+ /* compensate for month roll overs */
+ if (mday > 1)
+ mday = -1;
+ else if (mday < -1)
+ mday = 1;
+ /* update days for wday calculation */
+ days += mday;
+ /* handle yday */
+ if ((tim_p->tm_yday += mday) < 0) {
+ --year;
+ tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1;
+ } else {
+ mday = _DAYS_IN_YEAR(year);
+ if (tim_p->tm_yday > (mday - 1))
+ tim_p->tm_yday -= mday;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* add appropriate offset to put time in gmt format */
+ if (isdst == 1)
+ tim += (time_t) tz->__tzrule[1].offset;
+ else /* otherwise assume std time */
+ tim += (time_t) tz->__tzrule[0].offset;
+
+ TZ_UNLOCK;
+
+ /* reset isdst flag to what we have calculated */
+ tim_p->tm_isdst = isdst;
+
+ /* compute day of the week */
+ if ((tim_p->tm_wday = (days + 4) % 7) < 0)
+ tim_p->tm_wday += 7;
+
+ return tim;
+}
diff --git a/src/libc/newlib/src/time/month_lengths.c b/src/libc/newlib/src/time/month_lengths.c
new file mode 100644
index 0000000..03fac2f
--- /dev/null
+++ b/src/libc/newlib/src/time/month_lengths.c
@@ -0,0 +1,14 @@
+/*
+ * month_lengths.c
+ *
+ * Array __month_lengths[] is (indirectly) needed by tzset(), mktime(),
+ * gmtime() and localtime(). To break any dependencies, this array is moved to
+ * separate source file.
+ */
+
+#include "local.h"
+
+const int __month_lengths[2][MONSPERYEAR] = {
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+} ;
diff --git a/src/libc/newlib/src/time/tzcalc_limits.c b/src/libc/newlib/src/time/tzcalc_limits.c
new file mode 100644
index 0000000..00044a5
--- /dev/null
+++ b/src/libc/newlib/src/time/tzcalc_limits.c
@@ -0,0 +1,76 @@
+/*
+ * tzcalc_limits.c
+ * Original Author: Adapted from tzcode maintained by Arthur David Olson.
+ * Modifications:
+ * - Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
+ * - Fixed bug in mday computations - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
+ * - Fixed bug in __tzcalc_limits - 08/12/04, Alex Mogilnikov <alx@intellectronika.ru>
+ * - Moved __tzcalc_limits() to separate file - 05/09/14, Freddie Chopin <freddie_chopin@op.pl>
+ */
+
+#include "local.h"
+
+int
+__tzcalc_limits (int year)
+{
+ int days, year_days, years;
+ int i, j;
+ __tzinfo_type *const tz = __gettzinfo ();
+
+ if (year < EPOCH_YEAR)
+ return 0;
+
+ tz->__tzyear = year;
+
+ years = (year - EPOCH_YEAR);
+
+ year_days = years * 365 +
+ (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 -
+ (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
+ (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (tz->__tzrule[i].ch == 'J')
+ {
+ /* The Julian day n (1 <= n <= 365). */
+ days = year_days + tz->__tzrule[i].d +
+ (isleap(year) && tz->__tzrule[i].d >= 60);
+ /* Convert to yday */
+ --days;
+ }
+ else if (tz->__tzrule[i].ch == 'D')
+ days = year_days + tz->__tzrule[i].d;
+ else
+ {
+ const int yleap = isleap(year);
+ int m_day, m_wday, wday_diff;
+ const int *const ip = __month_lengths[yleap];
+
+ days = year_days;
+
+ for (j = 1; j < tz->__tzrule[i].m; ++j)
+ days += ip[j-1];
+
+ m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
+
+ wday_diff = tz->__tzrule[i].d - m_wday;
+ if (wday_diff < 0)
+ wday_diff += DAYSPERWEEK;
+ m_day = (tz->__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
+
+ while (m_day >= ip[j-1])
+ m_day -= DAYSPERWEEK;
+
+ days += m_day;
+ }
+
+ /* store the change-over time in GMT form by adding offset */
+ tz->__tzrule[i].change = (time_t) days * SECSPERDAY +
+ tz->__tzrule[i].s + tz->__tzrule[i].offset;
+ }
+
+ tz->__tznorth = (tz->__tzrule[0].change < tz->__tzrule[1].change);
+
+ return 1;
+}
diff --git a/src/libc/newlib/src/time/tzvars.c b/src/libc/newlib/src/time/tzvars.c
new file mode 100644
index 0000000..aabf3c4
--- /dev/null
+++ b/src/libc/newlib/src/time/tzvars.c
@@ -0,0 +1,9 @@
+#include <time.h>
+#include <sys/_tz_structs.h>
+
+/* Global timezone variables. */
+
+/* Default timezone to GMT */
+char *_tzname[2] = {"GMT", "GMT"};
+int _daylight = 0;
+long _timezone = 0;
diff --git a/src/libc/printf b/src/libc/printf
-Subproject d3b984684bb8a8bdc48cc7a1abecb93ce59bbe3
+Subproject 9baeae718716c41bc9a347810b33071a3718dd3
diff --git a/src/libc/private_include/libc/file.h b/src/libc/private_include/libc/file.h
index 3ba554c..dabeb89 100644
--- a/src/libc/private_include/libc/file.h
+++ b/src/libc/private_include/libc/file.h
@@ -1,15 +1,4 @@
#ifndef LIBC_FILE_H
#define LIBC_FILE_H
-enum
-{
- STDIN_FILENO,
- STDOUT_FILENO,
- STDERR_FILENO
-};
-
-struct __file
-{
-};
-
#endif
diff --git a/src/libc/private_include/libc/malloc.h b/src/libc/private_include/libc/malloc.h
new file mode 100644
index 0000000..2afdd9b
--- /dev/null
+++ b/src/libc/private_include/libc/malloc.h
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBC_MALLOC_H
+#define LIBC_MALLOC_H
+
+void __malloc_init(void);
+extern int __malloc_ta_init;
+
+#endif
diff --git a/src/libc/src/CMakeLists.txt b/src/libc/src/CMakeLists.txt
new file mode 100644
index 0000000..11e7a3c
--- /dev/null
+++ b/src/libc/src/CMakeLists.txt
@@ -0,0 +1,34 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ errno.c
+ ta_init.c
+)
+
+add_subdirectory(ctype)
+add_subdirectory(stdio)
+add_subdirectory(stdlib)
+add_subdirectory(string)
+
+if(NOT LIBC_FREESTANDING)
+ add_subdirectory(time)
+ add_subdirectory(unistd)
+endif()
+
+if(PS1_BUILD)
+ add_subdirectory(ps1)
+endif()
diff --git a/src/libc/src/ctype/CMakeLists.txt b/src/libc/src/ctype/CMakeLists.txt
new file mode 100644
index 0000000..8be1e2c
--- /dev/null
+++ b/src/libc/src/ctype/CMakeLists.txt
@@ -0,0 +1,24 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ isalpha.c
+ islower.c
+ isspace.c
+ isupper.c
+ tolower.c
+ toupper.c
+)
diff --git a/src/libc/src/ctype/isalpha.c b/src/libc/src/ctype/isalpha.c
new file mode 100644
index 0000000..bbc0256
--- /dev/null
+++ b/src/libc/src/ctype/isalpha.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+
+int isalpha(const int c)
+{
+ return islower(c) || isupper(c);
+}
diff --git a/src/libc/src/ctype/islower.c b/src/libc/src/ctype/islower.c
new file mode 100644
index 0000000..f30f7e7
--- /dev/null
+++ b/src/libc/src/ctype/islower.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+
+int islower(const int c)
+{
+ return c >= 'a' && c <= 'z';
+}
diff --git a/src/libc/src/ctype/isspace.c b/src/libc/src/ctype/isspace.c
new file mode 100644
index 0000000..a38d360
--- /dev/null
+++ b/src/libc/src/ctype/isspace.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+
+int isspace(const int c)
+{
+ return c == ' ' || c == '\t';
+}
diff --git a/src/libc/src/ctype/isupper.c b/src/libc/src/ctype/isupper.c
new file mode 100644
index 0000000..01a5644
--- /dev/null
+++ b/src/libc/src/ctype/isupper.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+
+int isupper(const int c)
+{
+ return c >= 'A' && c <= 'Z';
+}
diff --git a/src/libc/src/ctype/tolower.c b/src/libc/src/ctype/tolower.c
new file mode 100644
index 0000000..26c08fd
--- /dev/null
+++ b/src/libc/src/ctype/tolower.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+
+int tolower(const int c)
+{
+ if (isupper(c))
+ return c - 'A' + 'a';
+
+ return c;
+}
diff --git a/src/libc/src/ctype/toupper.c b/src/libc/src/ctype/toupper.c
new file mode 100644
index 0000000..e153a52
--- /dev/null
+++ b/src/libc/src/ctype/toupper.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+
+int toupper(const int c)
+{
+ if (islower(c))
+ return c - 'a' + 'A';
+
+ return c;
+}
diff --git a/src/libc/src/errno.c b/src/libc/src/errno.c
index d013499..3d6fe8b 100644
--- a/src/libc/src/errno.c
+++ b/src/libc/src/errno.c
@@ -1,3 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
#include <errno.h>
int errno;
diff --git a/src/libc/src/memcmp.c b/src/libc/src/memcmp.c
deleted file mode 100644
index f24d300..0000000
--- a/src/libc/src/memcmp.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <string.h>
-
-int memcmp(const void *const s1, const void *const s2, const size_t n)
-{
- const unsigned char *a = s1, *b = s2;
-
- for (size_t i = 0; i < n; i++, a++, b++)
- if (*a != *b)
- return *a - *b;
-
- return 0;
-}
diff --git a/src/libc/src/memcpy.c b/src/libc/src/memcpy.c
deleted file mode 100644
index 7014e63..0000000
--- a/src/libc/src/memcpy.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <string.h>
-#include <stddef.h>
-
-void *memcpy(void *const dst, const void *const src, const size_t n)
-{
- unsigned char *d = dst;
- const unsigned char *s = src;
-
- for (size_t i = 0; i < n; i++)
- *d++ = *s++;
-
- return dst;
-}
diff --git a/src/libc/src/memset.c b/src/libc/src/memset.c
deleted file mode 100644
index 90eb611..0000000
--- a/src/libc/src/memset.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <string.h>
-#include <stddef.h>
-
-void *memset(void *const dst, const int c, const size_t n)
-{
- unsigned char *d = dst;
-
- for (size_t i = 0; i < n; i++)
- *d++ = c;
-
- return dst;
-}
diff --git a/src/libc/src/ps1/CMakeLists.txt b/src/libc/src/ps1/CMakeLists.txt
new file mode 100644
index 0000000..54012df
--- /dev/null
+++ b/src/libc/src/ps1/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ putchar.c
+ setjmp.c
+)
+
+target_link_libraries(c PRIVATE drv_ps1_bios)
+target_compile_options(c PRIVATE -ffreestanding)
diff --git a/src/libc/src/ps1/putchar.c b/src/libc/src/ps1/putchar.c
new file mode 100644
index 0000000..81c98ec
--- /dev/null
+++ b/src/libc/src/ps1/putchar.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+int putchar(const int c)
+{
+ return EOF;
+}
+
+void _putchar(const char c)
+{
+ putchar(c);
+}
diff --git a/src/libc/src/ps1/setjmp.c b/src/libc/src/ps1/setjmp.c
new file mode 100644
index 0000000..40e488f
--- /dev/null
+++ b/src/libc/src/ps1/setjmp.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <setjmp.h>
+#include <drv/ps1/bios.h>
+
+int setjmp(jmp_buf buf)
+{
+ return SaveState(buf);
+}
diff --git a/src/libc/src/stdio/CMakeLists.txt b/src/libc/src/stdio/CMakeLists.txt
new file mode 100644
index 0000000..ca590a1
--- /dev/null
+++ b/src/libc/src/stdio/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ puts.c
+)
diff --git a/src/libc/src/stdio/puts.c b/src/libc/src/stdio/puts.c
new file mode 100644
index 0000000..262941a
--- /dev/null
+++ b/src/libc/src/stdio/puts.c
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+int puts(const char *s)
+{
+ for (; *s; s++)
+ if (putchar(*s) < 0)
+ return -1;
+
+ return putchar('\n');
+}
diff --git a/src/libc/src/stdlib/CMakeLists.txt b/src/libc/src/stdlib/CMakeLists.txt
new file mode 100644
index 0000000..f75b364
--- /dev/null
+++ b/src/libc/src/stdlib/CMakeLists.txt
@@ -0,0 +1,30 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ abort.c
+ abs.c
+ calloc.c
+ free.c
+ malloc.c
+ labs.c
+ llabs.c
+ realloc.c
+ strtol.c
+ strtoll.c
+ strtoul.c
+ strtoull.c
+)
diff --git a/src/libc/src/stdlib/abort.c b/src/libc/src/stdlib/abort.c
new file mode 100644
index 0000000..1fa6799
--- /dev/null
+++ b/src/libc/src/stdlib/abort.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+void __abort(const char *const filename, const int lineno)
+{
+ for (;;)
+ ;
+}
diff --git a/src/libc/src/malloc.c b/src/libc/src/stdlib/abs.c
index aa5ff31..785d060 100644
--- a/src/libc/src/malloc.c
+++ b/src/libc/src/stdlib/abs.c
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -17,9 +17,8 @@
*/
#include <stdlib.h>
-#include <stddef.h>
-void *malloc(const size_t __n)
+int abs(const int v)
{
- return NULL;
+ return v < 0 ? -v : v;
}
diff --git a/src/libc/src/stdlib/calloc.c b/src/libc/src/stdlib/calloc.c
new file mode 100644
index 0000000..c5e1dee
--- /dev/null
+++ b/src/libc/src/stdlib/calloc.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+void *calloc(const size_t nemb, const size_t size)
+{
+ const size_t n = nemb * size;
+ void *const ret = malloc(n);
+
+ if (ret)
+ memset(ret, 0, n);
+
+ return ret;
+}
diff --git a/src/libc/src/stdlib/free.c b/src/libc/src/stdlib/free.c
new file mode 100644
index 0000000..1986c48
--- /dev/null
+++ b/src/libc/src/stdlib/free.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tinyalloc.h>
+#include <libc/malloc.h>
+#include <stdlib.h>
+
+void free(void *const ptr)
+{
+ if (!ptr)
+ return;
+ else if (!__malloc_ta_init || !ta_free(ptr))
+ abort();
+}
diff --git a/src/libc/src/stdlib/labs.c b/src/libc/src/stdlib/labs.c
new file mode 100644
index 0000000..9759238
--- /dev/null
+++ b/src/libc/src/stdlib/labs.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+long labs(const long v)
+{
+ return v < 0 ? -v : v;
+}
diff --git a/src/libc/src/stdlib/llabs.c b/src/libc/src/stdlib/llabs.c
new file mode 100644
index 0000000..e737850
--- /dev/null
+++ b/src/libc/src/stdlib/llabs.c
@@ -0,0 +1,24 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+long long llabs(const long long v)
+{
+ return v < 0 ? -v : v;
+}
diff --git a/src/libc/src/stdlib/malloc.c b/src/libc/src/stdlib/malloc.c
new file mode 100644
index 0000000..81bdeb5
--- /dev/null
+++ b/src/libc/src/stdlib/malloc.c
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <libc/malloc.h>
+#include <tinyalloc.h>
+#include <errno.h>
+#include <stdint.h>
+
+void *malloc(const size_t n)
+{
+ if (!__malloc_ta_init)
+ {
+ /* README.md states 16 is a "good default value". */
+ if (!ta_init(1024, 16, sizeof (intmax_t)))
+ abort();
+
+ __malloc_ta_init = 1;
+ }
+
+ void *const ret = ta_alloc(n);
+
+ if (!ret)
+ errno = ENOMEM;
+
+ return ret;
+}
diff --git a/src/libc/src/stdlib/realloc.c b/src/libc/src/stdlib/realloc.c
new file mode 100644
index 0000000..dabfc05
--- /dev/null
+++ b/src/libc/src/stdlib/realloc.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <tinyalloc.h>
+#include <stdlib.h>
+
+void *realloc(void *const ptr, const size_t size)
+{
+ return ta_realloc(ptr, size);
+}
diff --git a/src/libc/src/stdlib/strtol.c b/src/libc/src/stdlib/strtol.c
new file mode 100644
index 0000000..b8dbdd9
--- /dev/null
+++ b/src/libc/src/stdlib/strtol.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+
+long strtol(const char *s, char **end, int base)
+{
+ long long v = strtoll(s, end, base);
+
+ if (v > LONG_MAX || v < LONG_MIN)
+ errno = ERANGE;
+
+ return v;
+}
diff --git a/src/libc/src/stdlib/strtoll.c b/src/libc/src/stdlib/strtoll.c
new file mode 100644
index 0000000..69f77d1
--- /dev/null
+++ b/src/libc/src/stdlib/strtoll.c
@@ -0,0 +1,91 @@
+/*
+ * Original source code from PSXSDK, by Giuseppe Gata.
+ * Released under a weak copyleft-like license, pasted below:
+ *
+ * You can use this library for any project, commercial and non-commercial,
+ * open-source and closed-source. But if you modify the library, you must
+ * redistribute the source for the modifications you did to it.
+ * Not doing that constitutes an infringement of this license.
+ * You are not obliged to redistribute the source code of this library if it
+ * was not modified at all by you or anyone related to you.
+ *
+ * There is no advertising clause; you aren't obliged to mention this library
+ * in any documentation of your work using it; however, it would be a nice gesture
+ * if you did so.
+ *
+ * These terms were written to not make people close this work which was released
+ * for all to share. In fact, no use is otherwise restricted.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+long long strtoll(const char *nptr, char **endptr, int base)
+{
+ int r = 0;
+ int t = 0;
+ int n = 0;
+
+ while(*nptr && isspace(*nptr))
+ nptr++;
+
+ if(*nptr == '-')
+ {
+ nptr++;
+ n = 1;
+ }
+
+ if(*nptr == '0')
+ {
+ if(*(nptr+1) == 'x' || *(nptr+1) == 'X')
+ {
+ if(base != 0 && base != 16)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ base = 16;
+ nptr+=2;
+ }
+ else if(base != 0 && base != 8)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+ else
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ if(base < 2 || base > 36)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ while(*nptr)
+ {
+ if (*nptr >= '0' && *nptr <= '9')
+ t = *nptr - '0';
+ else if (*nptr >= 'a' && *nptr <= 'z')
+ t = (*nptr - 'a') + 10;
+ else if (*nptr >= 'A' && *nptr <= 'Z')
+ t = (*nptr - 'A') + 10;
+ else
+ t = 1000;
+
+ if(t>=base)
+ break;
+
+ r*=base;
+ r+=t;
+ nptr++;
+ }
+
+ if(endptr)*endptr = (char*)nptr;
+ return n?-r:r;
+}
diff --git a/src/libc/src/stdlib/strtoul.c b/src/libc/src/stdlib/strtoul.c
new file mode 100644
index 0000000..f31c3dd
--- /dev/null
+++ b/src/libc/src/stdlib/strtoul.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+
+unsigned long strtoul(const char *s, char **end, int base)
+{
+ unsigned long long v = strtoull(s, end, base);
+
+ if (v > ULONG_MAX)
+ errno = ERANGE;
+
+ return v;
+}
diff --git a/src/libc/src/stdlib/strtoull.c b/src/libc/src/stdlib/strtoull.c
new file mode 100644
index 0000000..e8d2bd8
--- /dev/null
+++ b/src/libc/src/stdlib/strtoull.c
@@ -0,0 +1,85 @@
+/*
+ * Original source code from PSXSDK, by Giuseppe Gata.
+ * Released under a weak copyleft-like license, pasted below:
+ *
+ * You can use this library for any project, commercial and non-commercial,
+ * open-source and closed-source. But if you modify the library, you must
+ * redistribute the source for the modifications you did to it.
+ * Not doing that constitutes an infringement of this license.
+ * You are not obliged to redistribute the source code of this library if it
+ * was not modified at all by you or anyone related to you.
+ *
+ * There is no advertising clause; you aren't obliged to mention this library
+ * in any documentation of your work using it; however, it would be a nice gesture
+ * if you did so.
+ *
+ * These terms were written to not make people close this work which was released
+ * for all to share. In fact, no use is otherwise restricted.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+unsigned long long strtoull(const char *nptr, char **endptr, int base)
+{
+ int r = 0;
+ int t = 0;
+ int n = 0;
+
+ while(*nptr && isspace(*nptr))
+ nptr++;
+
+ if(*nptr == '0')
+ {
+ if(*(nptr+1) == 'x' || *(nptr+1) == 'X')
+ {
+ if(base != 0 && base != 16)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ base = 16;
+ nptr+=2;
+ }
+ else if(base != 0 && base != 8)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+ else
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ if(base < 2 || base > 36)
+ {
+ errno = EINVAL;
+ return 0;
+ }
+
+ while(*nptr)
+ {
+ if (*nptr >= '0' && *nptr <= '9')
+ t = *nptr - '0';
+ else if (*nptr >= 'a' && *nptr <= 'z')
+ t = (*nptr - 'a') + 10;
+ else if (*nptr >= 'A' && *nptr <= 'Z')
+ t = (*nptr - 'A') + 10;
+ else
+ t = 1000;
+
+ if(t>=base)
+ break;
+
+ r*=base;
+ r+=t;
+ nptr++;
+ }
+
+ if(endptr)*endptr = (char*)nptr;
+ return n?-r:r;
+}
diff --git a/src/libc/src/streams.c b/src/libc/src/streams.c
deleted file mode 100644
index 95289e3..0000000
--- a/src/libc/src/streams.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include <libc/file.h>
-#include <stdio.h>
-
-static FILE f[3];
-FILE *stdin = &f[STDIN_FILENO], *stdout = &f[STDOUT_FILENO],
- *stderr = &f[STDERR_FILENO];
diff --git a/src/libc/src/strerror.c b/src/libc/src/strerror.c
deleted file mode 100644
index 6444e98..0000000
--- a/src/libc/src/strerror.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <string.h>
-#include <errno.h>
-
-char *strerror(const int errnum)
-{
- static const char *const s[] =
- {
- [EPERM] = "Operation not permitted",
- [ENOENT] = "No such file or directory",
- [ESRCH] = "No such process",
- [EINTR] = "Interrupted system call",
- [EIO] = "Input/output error",
- [ENXIO] = "No such device or address",
- [E2BIG] = "Argument list too long",
- [ENOEXEC] = "Exec format error",
- [EBADF] = "Bad file descriptor",
- [ECHILD] = "No child processes",
- [EAGAIN] = "Resource temporarily unavailable",
- [ENOMEM] = "Cannot allocate memory",
- [EACCES] = "Permission denied",
- [EFAULT] = "Bad address",
- [ENOTBLK] = "Block device required",
- [EBUSY] = "Device or resource busy",
- [EEXIST] = "File exists",
- [EXDEV] = "Invalid cross-device link",
- [ENODEV] = "No such device",
- [ENOTDIR] = "Not a directory",
- [EISDIR] = "Is a directory",
- [EINVAL] = "Invalid argument",
- [ENFILE] = "Too many open files in system",
- [EMFILE] = "Too many open files",
- [ENOTTY] = "Inappropriate ioctl for device",
- [ETXTBSY] = "Text file busy",
- [EFBIG] = "File too large",
- [ENOSPC] = "No space left on device",
- [ESPIPE] = "Illegal seek",
- [EROFS] = "Read-only file system",
- [EMLINK] = "Too many links",
- [EPIPE] = "Broken pipe",
- };
-
- if (errnum < 0 || errnum >= sizeof s / sizeof *s)
- return "Unknown errno";
-
- return (char *)s[errnum];
-}
diff --git a/src/libc/src/string/CMakeLists.txt b/src/libc/src/string/CMakeLists.txt
new file mode 100644
index 0000000..b0c565f
--- /dev/null
+++ b/src/libc/src/string/CMakeLists.txt
@@ -0,0 +1,32 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ memcmp.c
+ memcpy.c
+ memset.c
+ strcasecmp.c
+ strchr.c
+ strcmp.c
+ strdup.c
+ strerror.c
+ strlen.c
+ strncmp.c
+ strndup.c
+ strpbrk.c
+ strrchr.c
+ strspn.c
+)
diff --git a/src/libc/src/string/memcmp.c b/src/libc/src/string/memcmp.c
new file mode 100644
index 0000000..33a6a6d
--- /dev/null
+++ b/src/libc/src/string/memcmp.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+int memcmp(const void *const s1, const void *const s2, const size_t n)
+{
+ const unsigned char *a = s1, *b = s2;
+
+ for (size_t i = 0; i < n; i++, a++, b++)
+ if (*a != *b)
+ return *a - *b;
+
+ return 0;
+}
diff --git a/src/libc/src/string/memcpy.c b/src/libc/src/string/memcpy.c
new file mode 100644
index 0000000..b82f9b5
--- /dev/null
+++ b/src/libc/src/string/memcpy.c
@@ -0,0 +1,57 @@
+/*
+ * Original source code from PSXSDK, by Xavier Del Campo Romero.
+ * Released under a weak copyleft-like license, pasted below:
+ *
+ * You can use this library for any project, commercial and non-commercial,
+ * open-source and closed-source. But if you modify the library, you must
+ * redistribute the source for the modifications you did to it.
+ * Not doing that constitutes an infringement of this license.
+ * You are not obliged to redistribute the source code of this library if it
+ * was not modified at all by you or anyone related to you.
+ *
+ * There is no advertising clause; you aren't obliged to mention this library
+ * in any documentation of your work using it; however, it would be a nice gesture
+ * if you did so.
+ *
+ * These terms were written to not make people close this work which was released
+ * for all to share. In fact, no use is otherwise restricted.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+void *memcpy(void *const dst, const void *const src, size_t n)
+{
+ union
+ {
+ const void *v;
+ const unsigned char *c;
+ const unsigned int *w;
+ } srcl;
+
+ union
+ {
+ void *v;
+ unsigned char *c;
+ unsigned int *w;
+ } dstl;
+
+ srcl.v = src;
+ dstl.v = dst;
+
+ /* Avoid unaligned access before doing word access. */
+ while (n && (((ptrdiff_t)dstl.v & (sizeof (int) - 1))
+ || ((ptrdiff_t)srcl.v & (sizeof (int) - 1))))
+ {
+ *dstl.c++ = *srcl.c++;
+ n--;
+ }
+
+ for (; n >= sizeof (int); n -= sizeof (int))
+ *dstl.w++ = *srcl.w++;
+
+ while (n--)
+ *dstl.c++ = *srcl.c++;
+
+ return dst;
+}
diff --git a/src/libc/src/string/memset.c b/src/libc/src/string/memset.c
new file mode 100644
index 0000000..a68aa32
--- /dev/null
+++ b/src/libc/src/string/memset.c
@@ -0,0 +1,46 @@
+/*
+ * Original source code from PSXSDK, by Giuseppe Gata.
+ * Released under a weak copyleft-like license, pasted below:
+ *
+ * You can use this library for any project, commercial and non-commercial,
+ * open-source and closed-source. But if you modify the library, you must
+ * redistribute the source for the modifications you did to it.
+ * Not doing that constitutes an infringement of this license.
+ * You are not obliged to redistribute the source code of this library if it
+ * was not modified at all by you or anyone related to you.
+ *
+ * There is no advertising clause; you aren't obliged to mention this library
+ * in any documentation of your work using it; however, it would be a nice gesture
+ * if you did so.
+ *
+ * These terms were written to not make people close this work which was released
+ * for all to share. In fact, no use is otherwise restricted.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+void *memset(void *const dst, const int c, size_t n)
+{
+ union
+ {
+ void *v;
+ unsigned char *c;
+ unsigned *w;
+ } dstl = {.v = dst};
+
+ /* Avoid unaligned access before doing word access. */
+ while (n && ((ptrdiff_t)dstl.v & (sizeof *dstl.w - 1)))
+ {
+ *dstl.c++ = c;
+ n--;
+ }
+
+ for (; n >= sizeof *dstl.w; n -= sizeof *dstl.w)
+ *dstl.w++ = c;
+
+ while (n--)
+ *dstl.c++ = c;
+
+ return dst;
+}
diff --git a/src/libc/src/string/strcasecmp.c b/src/libc/src/string/strcasecmp.c
new file mode 100644
index 0000000..fbc4463
--- /dev/null
+++ b/src/libc/src/string/strcasecmp.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strcasecmp(const char *a, const char *b)
+{
+ while (*a && *b)
+ {
+ const unsigned char ac = *a, bc = *b;
+
+ if (isalpha(ac) && isalpha(bc))
+ if (toupper(ac) != toupper(bc))
+ break;
+
+ a++;
+ b++;
+ }
+
+ return !!*a || !!*b;
+}
diff --git a/src/libc/src/strchr.c b/src/libc/src/string/strchr.c
index 3a1fd0b..3a1fd0b 100644
--- a/src/libc/src/strchr.c
+++ b/src/libc/src/string/strchr.c
diff --git a/src/libc/src/string/strcmp.c b/src/libc/src/string/strcmp.c
new file mode 100644
index 0000000..aa96e3c
--- /dev/null
+++ b/src/libc/src/string/strcmp.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+int strcmp(const char *a, const char *b)
+{
+ while (*a && *b && *a++ == *b++)
+ ;
+
+ return !!*a || !!*b;
+}
diff --git a/src/libc/src/string/strcspn.c b/src/libc/src/string/strcspn.c
new file mode 100644
index 0000000..7c87caf
--- /dev/null
+++ b/src/libc/src/string/strcspn.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+size_t strcspn(const char *s, const char *const reject)
+{
+ size_t ret = 0;
+
+ while (!strpbrk(s++, reject))
+ ret++;
+
+ return ret;
+}
diff --git a/src/libc/src/string/strdup.c b/src/libc/src/string/strdup.c
new file mode 100644
index 0000000..226ef68
--- /dev/null
+++ b/src/libc/src/string/strdup.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strdup(const char *const s)
+{
+ const size_t n = strlen(s) + 1;
+ char *const ret = malloc(n);
+
+ if (!ret)
+ return NULL;
+
+ memcpy(ret, s, n);
+ return ret;
+}
diff --git a/src/libc/src/string/strerror.c b/src/libc/src/string/strerror.c
new file mode 100644
index 0000000..64f13de
--- /dev/null
+++ b/src/libc/src/string/strerror.c
@@ -0,0 +1,181 @@
+/* Copyright (C) 1991-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <errno.h>
+
+char *strerror(const int errnum)
+{
+ static const char *const s[] =
+ {
+ [SUCCESS] = "Success",
+ [EPERM] = "Operation not permitted",
+ [ENOENT] = "No such file or directory",
+ [ESRCH] = "No such process",
+ [EINTR] = "Interrupted system call",
+ [EIO] = "Input/output error",
+ [ENXIO] = "No such device or address",
+ [E2BIG] = "Argument list too long",
+ [ENOEXEC] = "Exec format error",
+ [EBADF] = "Bad file descriptor",
+ [ECHILD] = "No child processes",
+ [EAGAIN] = "Resource temporarily unavailable",
+ [ENOMEM] = "Cannot allocate memory",
+ [EACCES] = "Permission denied",
+ [EFAULT] = "Bad address",
+ [ENOTBLK] = "Block device required",
+ [EBUSY] = "Device or resource busy",
+ [EEXIST] = "File exists",
+ [EXDEV] = "Invalid cross-device link",
+ [ENODEV] = "No such device",
+ [ENOTDIR] = "Not a directory",
+ [EISDIR] = "Is a directory",
+ [EINVAL] = "Invalid argument",
+ [ENFILE] = "Too many open files in system",
+ [EMFILE] = "Too many open files",
+ [ENOTTY] = "Inappropriate ioctl for device",
+ [ETXTBSY] = "Text file busy",
+ [EFBIG] = "File too large",
+ [ENOSPC] = "No space left on device",
+ [ESPIPE] = "Illegal seek",
+ [EROFS] = "Read-only file system",
+ [EMLINK] = "Too many links",
+ [EPIPE] = "Broken pipe",
+ [EDOM] = "Numerical argument out of domain",
+ [ERANGE] = "Numerical result out of range",
+ [EDEADLK] = "Resource deadlock avoided",
+ [ENAMETOOLONG] = "File name too long",
+ [ENOLCK] = "No locks available",
+ [ENOSYS] = "Function not implemented",
+ [ENOTEMPTY] = "Directory not empty",
+ [ELOOP] = "Too many levels of symbolic links",
+ [ENOMSG] = "No message of desired type",
+ [EIDRM] = "Identifier removed",
+ [ECHRNG] = "Channel number out of range",
+ [EL2NSYNC] = "Level 2 not synchronized",
+ [EL3HLT] = "Level 3 halted",
+ [EL3RST] = "Level 3 reset",
+ [ELNRNG] = "Link number out of range",
+ [EUNATCH] = "Protocol driver not attached",
+ [ENOCSI] = "No CSI structure available",
+ [EL2HLT] = "Level 2 halted",
+ [EBADE] = "Invalid exchange",
+ [EBADR] = "Invalid request descriptor",
+ [EXFULL] = "Exchange full",
+ [ENOANO] = "No anode",
+ [EBADRQC] = "Invalid request code",
+ [EBADSLT] = "Invalid slot",
+ [EBFONT] = "Bad font file format",
+ [ENOSTR] = "Device not a stream",
+ [ENODATA] = "No data available",
+ [ETIME] = "Timer expired",
+ [ENOSR] = "Out of streams resources",
+ [ENONET] = "Machine is not on the network",
+ [ENOPKG] = "Package not installed",
+ [EREMOTE] = "Object is remote",
+ [ENOLINK] = "Link has been severed",
+ [EADV] = "Advertise error",
+ [ESRMNT] = "Srmount error",
+ [ECOMM] = "Communication error on send",
+ [EPROTO] = "Protocol error",
+ [EMULTIHOP] = "Multihop attempted",
+ [EDOTDOT] = "RFS specific error",
+ [EBADMSG] = "Bad message",
+ [EOVERFLOW] = "Value too large for defined data type",
+ [ENOTUNIQ] = "Name not unique on network",
+ [EBADFD] = "File descriptor in bad state",
+ [EREMCHG] = "Remote address changed",
+ [ELIBACC] = "Can not access a needed shared library",
+ [ELIBBAD] = "Accessing a corrupted shared library",
+ [ELIBSCN] = ".lib section in a.out corrupted",
+ [ELIBMAX] = "Attempting to link in too many shared libraries",
+ [ELIBEXEC] = "Cannot exec a shared library directly",
+ [EILSEQ] = "Invalid or incomplete multibyte or wide character",
+ [ERESTART] = "Interrupted system call should be restarted",
+ [ESTRPIPE] = "Streams pipe error",
+ [EUSERS] = "Too many users",
+ [ENOTSOCK] = "Socket operation on non-socket",
+ [EDESTADDRREQ] = "Destination address required",
+ [EMSGSIZE] = "Message too long",
+ [EPROTOTYPE] = "Protocol wrong type for socket",
+ [ENOPROTOOPT] = "Protocol not available",
+ [EPROTONOSUPPORT] = "Protocol not supported",
+ [ESOCKTNOSUPPORT] = "Socket type not supported",
+ [ENOTSUP] = "Operation not supported",
+ [EPFNOSUPPORT] = "Protocol family not supported",
+ [EAFNOSUPPORT] = "Address family not supported by protocol",
+ [EADDRINUSE] = "Address already in use",
+ [EADDRNOTAVAIL] = "Cannot assign requested address",
+ [ENETDOWN] = "Network is down",
+ [ENETUNREACH] = "Network is unreachable",
+ [ENETRESET] = "Network dropped connection on reset",
+ [ECONNABORTED] = "Software caused connection abort",
+ [ECONNRESET] = "Connection reset by peer",
+ [ENOBUFS] = "No buffer space available",
+ [EISCONN] = "Transport endpoint is already connected",
+ [ENOTCONN] = "Transport endpoint is not connected",
+ [ESHUTDOWN] = "Cannot send after transport endpoint shutdown",
+ [ETOOMANYREFS] = "Too many references: cannot splice",
+ [ETIMEDOUT] = "Connection timed out",
+ [ECONNREFUSED] = "Connection refused",
+ [EHOSTDOWN] = "Host is down",
+ [EHOSTUNREACH] = "No route to host",
+ [EALREADY] = "Operation already in progress",
+ [EINPROGRESS] = "Operation now in progress",
+ [ESTALE] = "Stale file handle",
+ [EUCLEAN] = "Structure needs cleaning",
+ [ENOTNAM] = "Not a XENIX named type file",
+ [ENAVAIL] = "No XENIX semaphores available",
+ [EISNAM] = "Is a named type file",
+ [EREMOTEIO] = "Remote I/O error",
+ [EDQUOT] = "Disk quota exceeded",
+ [ENOMEDIUM] = "No medium found",
+ [EMEDIUMTYPE] = "Wrong medium type",
+ [ECANCELED] = "Operation canceled",
+ [ENOKEY] = "Required key not available",
+ [EKEYEXPIRED] = "Key has expired",
+ [EKEYREVOKED] = "Key has been revoked",
+ [EKEYREJECTED] = "Key was rejected by service",
+ [EOWNERDEAD] = "Owner died",
+ [ENOTRECOVERABLE] = "State not recoverable",
+ [ERFKILL] = "Operation not possible due to RF-kill",
+ [EHWPOISON] = "Memory page has hardware error",
+ };
+
+ if (errnum < 0 || errnum >= sizeof s / sizeof *s)
+ return "Unknown errno";
+
+ return (char *)s[errnum];
+}
diff --git a/src/libc/src/string/strlen.c b/src/libc/src/string/strlen.c
new file mode 100644
index 0000000..d2d1146
--- /dev/null
+++ b/src/libc/src/string/strlen.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+size_t strlen(const char *s)
+{
+ size_t ret = 0;
+
+ while (*s++)
+ ret++;
+
+ return ret;
+}
diff --git a/src/libc/src/string/strncmp.c b/src/libc/src/string/strncmp.c
new file mode 100644
index 0000000..dc583e7
--- /dev/null
+++ b/src/libc/src/string/strncmp.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+int strncmp(const char *a, const char *b, const size_t n)
+{
+ for (size_t i = 0; i < n; i++)
+ if (!*a || !*b || *a++ != *b++)
+ return -1;
+
+ return 0;
+}
diff --git a/src/libc/src/string/strndup.c b/src/libc/src/string/strndup.c
new file mode 100644
index 0000000..3815c01
--- /dev/null
+++ b/src/libc/src/string/strndup.c
@@ -0,0 +1,32 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strndup(const char *const s, const size_t n)
+{
+ char *const ret = malloc(n + 1);
+
+ if (!ret)
+ return NULL;
+
+ memcpy(ret, s, n);
+ ret[n] = '\0';
+ return ret;
+}
diff --git a/src/libc/src/string/strpbrk.c b/src/libc/src/string/strpbrk.c
new file mode 100644
index 0000000..ac618fa
--- /dev/null
+++ b/src/libc/src/string/strpbrk.c
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+char *strpbrk(const char *const s, const char *accept)
+{
+ char c, *ret = NULL;
+
+ while ((c = *accept++))
+ {
+ char *p = strchr(s, c);
+
+ if (!p)
+ continue;
+ else if (!ret || ret > p)
+ ret = p;
+ }
+
+ return ret;
+}
diff --git a/src/libc/src/string/strrchr.c b/src/libc/src/string/strrchr.c
new file mode 100644
index 0000000..1d7a8fa
--- /dev/null
+++ b/src/libc/src/string/strrchr.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+char *strrchr(const char *s, const int c)
+{
+ const size_t len = strlen(s);
+
+ for (size_t i = len; i <= len; i--)
+ if (s[i] == c)
+ return (char *)&s[i];
+
+ return NULL;
+}
diff --git a/src/libc/src/string/strspn.c b/src/libc/src/string/strspn.c
new file mode 100644
index 0000000..25e6cef
--- /dev/null
+++ b/src/libc/src/string/strspn.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+size_t strspn(const char *s, const char *const accept)
+{
+ size_t ret = 0;
+
+ while (*s)
+ {
+ const char *const ss = strpbrk(s, accept);
+
+ if (ss == s)
+ ret++;
+ else if (ret)
+ return ret;
+
+ s++;
+ }
+
+ return ret;
+}
diff --git a/src/libc/src/strlen.c b/src/libc/src/strlen.c
deleted file mode 100644
index 43efcc5..0000000
--- a/src/libc/src/strlen.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <string.h>
-#include <stddef.h>
-
-size_t strlen(const char *s)
-{
- size_t ret = 0;
-
- while (*s++)
- ret++;
-
- return ret;
-}
diff --git a/src/libc/src/ta_init.c b/src/libc/src/ta_init.c
new file mode 100644
index 0000000..118f62a
--- /dev/null
+++ b/src/libc/src/ta_init.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <libc/malloc.h>
+
+int __malloc_ta_init;
diff --git a/src/libc/src/time/CMakeLists.txt b/src/libc/src/time/CMakeLists.txt
new file mode 100644
index 0000000..907811d
--- /dev/null
+++ b/src/libc/src/time/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ clock_getres.c
+ clock_gettime.c
+ clock_settime.c
+)
diff --git a/src/libc/src/time/clock_getres.c b/src/libc/src/time/clock_getres.c
new file mode 100644
index 0000000..84d0f39
--- /dev/null
+++ b/src/libc/src/time/clock_getres.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <drv/time.h>
+
+int clock_getres(const clockid_t id, struct timespec *const ts)
+{
+ return drv_time_getres(id, ts);
+}
diff --git a/src/libc/src/time/clock_gettime.c b/src/libc/src/time/clock_gettime.c
new file mode 100644
index 0000000..8d124a5
--- /dev/null
+++ b/src/libc/src/time/clock_gettime.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <drv/time.h>
+
+int clock_gettime(const clockid_t id, struct timespec *const ts)
+{
+ return drv_time_gettime(id, ts);
+}
diff --git a/src/libc/src/time/clock_settime.c b/src/libc/src/time/clock_settime.c
new file mode 100644
index 0000000..08dc7e1
--- /dev/null
+++ b/src/libc/src/time/clock_settime.c
@@ -0,0 +1,25 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <drv/time.h>
+
+int clock_settime(const clockid_t id, const struct timespec *const ts)
+{
+ return drv_time_settime(id, ts);
+}
diff --git a/src/libc/src/unistd/CMakeLists.txt b/src/libc/src/unistd/CMakeLists.txt
new file mode 100644
index 0000000..a896727
--- /dev/null
+++ b/src/libc/src/unistd/CMakeLists.txt
@@ -0,0 +1,19 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(c PRIVATE
+ sbrk.c
+)
diff --git a/src/libc/src/unistd/sbrk.c b/src/libc/src/unistd/sbrk.c
new file mode 100644
index 0000000..459d476
--- /dev/null
+++ b/src/libc/src/unistd/sbrk.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+
+extern char __bss_end[], __ram_end[];
+static char *base = __bss_end;
+
+void *sbrk(const intptr_t increment)
+{
+
+
+
+ if (base + increment >= __ram_end)
+ return NULL;
+
+ void *p = base;
+
+ base += increment;
+ return p;
+}
diff --git a/src/libc/tinyalloc b/src/libc/tinyalloc
-Subproject 30457f9169c9f21c5ffee8b393cd977137ab446
+Subproject fd8128d9b84e362abdbd05fafe252421edee8ab
diff --git a/src/loop/CMakeLists.txt b/src/loop/CMakeLists.txt
new file mode 100644
index 0000000..5d1e3e2
--- /dev/null
+++ b/src/loop/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(loop)
+add_subdirectory(src)
+target_include_directories(loop PUBLIC include PRIVATE private_include)
+target_link_libraries(loop PUBLIC aio PRIVATE bin fs gfx init net)
diff --git a/src/loop/include/loop.h b/src/loop/include/loop.h
new file mode 100644
index 0000000..e6ccb29
--- /dev/null
+++ b/src/loop/include/loop.h
@@ -0,0 +1,28 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef LOOP_H
+#define LOOP_H
+
+#include <aio.h>
+
+int loop_run(void);
+int loop_add_aio(struct aio *a);
+int loop_rm_aio(struct aio *a);
+
+#endif
diff --git a/src/loop/private_include/loop/types.h b/src/loop/private_include/loop/types.h
new file mode 100644
index 0000000..fb345d0
--- /dev/null
+++ b/src/loop/private_include/loop/types.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef LOOP_TYPES_H
+#define LOOP_TYPES_H
+
+#include <aio.h>
+
+extern struct aio_poll *loop_aio_head, *loop_aio_tail;
+
+#endif
diff --git a/src/loop/src/CMakeLists.txt b/src/loop/src/CMakeLists.txt
new file mode 100644
index 0000000..8fcedfa
--- /dev/null
+++ b/src/loop/src/CMakeLists.txt
@@ -0,0 +1,22 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(loop PRIVATE
+ add_aio.c
+ globals.c
+ rm_aio.c
+ run.c
+)
diff --git a/src/loop/src/add_aio.c b/src/loop/src/add_aio.c
new file mode 100644
index 0000000..a71d482
--- /dev/null
+++ b/src/loop/src/add_aio.c
@@ -0,0 +1,43 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <loop.h>
+#include <loop/types.h>
+#include <aio.h>
+#include <stdlib.h>
+
+int loop_add_aio(struct aio *const a)
+{
+ struct aio_poll *const p = malloc(sizeof *p);
+
+ if (!p)
+ return -1;
+
+ *p = (const struct aio_poll){.aio = a};
+
+ if (!loop_aio_head)
+ loop_aio_head = p;
+ else if (loop_aio_tail)
+ {
+ loop_aio_tail->next = p;
+ p->prev = loop_aio_tail;
+ }
+
+ loop_aio_tail = p;
+ return 0;
+}
diff --git a/src/loop/src/globals.c b/src/loop/src/globals.c
new file mode 100644
index 0000000..429d936
--- /dev/null
+++ b/src/loop/src/globals.c
@@ -0,0 +1,21 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <loop/types.h>
+
+struct aio_poll *loop_aio_head, *loop_aio_tail;
diff --git a/src/loop/src/rm_aio.c b/src/loop/src/rm_aio.c
new file mode 100644
index 0000000..5d4f159
--- /dev/null
+++ b/src/loop/src/rm_aio.c
@@ -0,0 +1,48 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <loop.h>
+#include <loop/types.h>
+#include <aio.h>
+#include <stdlib.h>
+
+int loop_rm_aio(struct aio *const aio)
+{
+ for (struct aio_poll *p = loop_aio_head; p; p = p->next)
+ if (p->aio == aio)
+ {
+ struct aio_poll *const prev = p->prev, *const next = p->next;
+
+ if (!prev)
+ {
+ loop_aio_head = next;
+
+ if (next)
+ next->prev = NULL;
+ }
+ else if ((prev->next = next))
+ next->prev = prev;
+ else
+ loop_aio_tail = prev;
+
+ free(p);
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/src/loop/src/run.c b/src/loop/src/run.c
new file mode 100644
index 0000000..ea3ef26
--- /dev/null
+++ b/src/loop/src/run.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <loop.h>
+#include <loop/types.h>
+#include <aio.h>
+#include <bin.h>
+#include <fs/fs.h>
+#include <gfx/gfx.h>
+#include <init.h>
+#include <net.h>
+
+int loop_run(void)
+{
+ if (fs_update()
+ || aio_poll(loop_aio_head, 0) < 0
+ || init_run()
+ || net_update()
+ || bin_update()
+ || gfx_update())
+ return -1;
+
+ return 0;
+}
diff --git a/src/main.c b/src/main.c
index 99d4c95..3a28e28 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,5 @@
/*
- * wanix, a Unix-like operating system for WebAssembly
+ * wnix, a Unix-like operating system for WebAssembly applications.
* Copyright (C) 2025 Xavier Del Campo Romero
*
* This program is free software: you can redistribute it and/or modify
@@ -16,31 +16,19 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-#include <aio.h>
-#include <errno.h>
-#include <stdio.h>
+#include <init.h>
+#include <gfx/gfx.h>
+#include <loop.h>
#include <stdlib.h>
-#include <string.h>
int main(void)
{
- int ret = EXIT_FAILURE;
- struct aio *aio = aio_open("/media/cdrom/", "rb");
+ if (init_port() || init_time() || gfx_init() || init_boot() || init_vfs())
+ return EXIT_FAILURE;
- if (!aio)
- {
- fprintf(stderr, "%s: aio_open failed: %s\n", __func__, strerror(errno));
- goto end;
- }
+ for (;;)
+ if (loop_run())
+ return EXIT_FAILURE;
- ret = EXIT_SUCCESS;
-
-end:
- if (aio && aio_close(aio))
- {
- fprintf(stderr, "%s: aio_close failed: %s\n", __func__, strerror(errno));
- ret = EXIT_FAILURE;
- }
-
- return ret;
+ return EXIT_SUCCESS;
}
diff --git a/src/nanowasm b/src/nanowasm
-Subproject d65c912cb571f6e4946bfd7cbdfcdf4204d09b7
+Subproject 1e3a4e9ff4d9963aa77dc6135f351f90d927e9e
diff --git a/src/net/CMakeLists.txt b/src/net/CMakeLists.txt
new file mode 100644
index 0000000..e0822e7
--- /dev/null
+++ b/src/net/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(net)
+add_subdirectory(src)
+target_include_directories(net PUBLIC include PRIVATE private_include)
+target_link_libraries(net PRIVATE aio loop state wip)
diff --git a/src/net/include/net.h b/src/net/include/net.h
new file mode 100644
index 0000000..0ae9dc1
--- /dev/null
+++ b/src/net/include/net.h
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef NET_H
+#define NET_H
+
+int net_init(const char *dev);
+int net_update(void);
+int net_shutdown(void);
+
+#endif
diff --git a/src/net/private_include/net/ops.h b/src/net/private_include/net/ops.h
new file mode 100644
index 0000000..abeea39
--- /dev/null
+++ b/src/net/private_include/net/ops.h
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef NET_OPS_H
+#define NET_OPS_H
+
+#include <stddef.h>
+
+void *net_alloc(size_t n, void *user);
+void *net_realloc(void *, size_t n, void *user);
+void net_free(void *p, void *user);
+int net_read(void *buf, size_t n, void *user);
+int net_write(const void *buf, size_t n, void *user);
+
+#endif
diff --git a/src/net/private_include/net/types.h b/src/net/private_include/net/types.h
new file mode 100644
index 0000000..eab5843
--- /dev/null
+++ b/src/net/private_include/net/types.h
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef NET_TYPES_H
+#define NET_TYPES_H
+
+#include <aio.h>
+#include <fs/fs.h>
+#include <wip/wip.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+struct net
+{
+ bool init;
+ size_t available;
+ struct aio *aio;
+ struct wip w;
+ struct fs_fd fd;
+};
+
+extern struct net net;
+
+#endif
diff --git a/src/net/src/CMakeLists.txt b/src/net/src/CMakeLists.txt
new file mode 100644
index 0000000..c011446
--- /dev/null
+++ b/src/net/src/CMakeLists.txt
@@ -0,0 +1,24 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(net PRIVATE
+ init.c
+ net.c
+ shutdown.c
+ update.c
+)
+
+add_subdirectory(ops)
diff --git a/src/net/src/init.c b/src/net/src/init.c
new file mode 100644
index 0000000..9e66981
--- /dev/null
+++ b/src/net/src/init.c
@@ -0,0 +1,78 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/ops.h>
+#include <net/types.h>
+#include <aio.h>
+#include <loop.h>
+#include <wip/wip.h>
+#include <fcntl.h>
+#include <stdbool.h>
+
+static int open_done(const enum state state, void *const args)
+{
+ struct net *const n = &net;
+
+ if (loop_rm_aio(n->aio))
+ return -1;
+
+ aio_free(n->aio);
+ n->aio = NULL;
+ n->init = true;
+ return 0;
+}
+
+int net_init(const char *const dev)
+{
+ struct net *const n = &net;
+ struct aio *aio = NULL;
+ const struct wip_cfg cfg =
+ {
+ .alloc = net_alloc,
+ .realloc = net_realloc,
+ .free = net_free,
+ .read = net_read,
+ .write = net_write,
+ .user = n
+ };
+
+ const struct fs_open op =
+ {
+ .path = dev,
+ .fd = &n->fd,
+ .flags = O_RDWR
+ };
+
+ const struct aio_done d =
+ {
+ .f = open_done,
+ .args = n
+ };
+
+ if (!(aio = aio_open(&op, &d)) || loop_add_aio(aio))
+ goto failure;
+
+ *n = (const struct net){.aio = aio};
+ wip_init(&n->w, &cfg);
+ return 0;
+
+failure:
+ aio_free(aio);
+ return -1;
+}
diff --git a/src/net/src/net.c b/src/net/src/net.c
new file mode 100644
index 0000000..b2dbd1a
--- /dev/null
+++ b/src/net/src/net.c
@@ -0,0 +1,22 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/types.h>
+
+struct net net;
diff --git a/src/net/src/ops/CMakeLists.txt b/src/net/src/ops/CMakeLists.txt
new file mode 100644
index 0000000..40d4490
--- /dev/null
+++ b/src/net/src/ops/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(net PRIVATE
+ alloc.c
+ free.c
+ read.c
+ realloc.c
+ write.c
+)
diff --git a/src/net/src/ops/alloc.c b/src/net/src/ops/alloc.c
new file mode 100644
index 0000000..6152a92
--- /dev/null
+++ b/src/net/src/ops/alloc.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/ops.h>
+#include <net/types.h>
+#include <wip/wip.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void *net_alloc(const size_t n, void *const user)
+{
+ return malloc(n);
+}
diff --git a/src/net/src/ops/free.c b/src/net/src/ops/free.c
new file mode 100644
index 0000000..0f1f63b
--- /dev/null
+++ b/src/net/src/ops/free.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/ops.h>
+#include <net/types.h>
+#include <wip/wip.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void net_free(void *const p, void *const user)
+{
+ free(p);
+}
diff --git a/src/net/src/ops/read.c b/src/net/src/ops/read.c
new file mode 100644
index 0000000..1fca206
--- /dev/null
+++ b/src/net/src/ops/read.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/ops.h>
+#include <net/types.h>
+#include <aio.h>
+#include <loop.h>
+#include <wip/wip.h>
+#include <stddef.h>
+
+int net_read(void *const buf, const size_t n, void *const user)
+{
+ struct net *const net = user;
+ const struct fs_read r =
+ {
+ .fd = &net->fd,
+ .buf = buf,
+ .n = n
+ };
+
+ return aio_read_nb(&r);
+}
diff --git a/src/net/src/ops/realloc.c b/src/net/src/ops/realloc.c
new file mode 100644
index 0000000..329cbe5
--- /dev/null
+++ b/src/net/src/ops/realloc.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/ops.h>
+#include <net/types.h>
+#include <wip/wip.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void *net_realloc(void *const p, const size_t n, void *const user)
+{
+ return realloc(p, n);
+}
diff --git a/src/net/src/ops/write.c b/src/net/src/ops/write.c
new file mode 100644
index 0000000..2bf9093
--- /dev/null
+++ b/src/net/src/ops/write.c
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/ops.h>
+#include <net/types.h>
+#include <wip/wip.h>
+#include <stddef.h>
+
+int net_write(const void *const buf, const size_t n, void *const user)
+{
+ /* TODO */
+ return -1;
+}
diff --git a/src/net/src/shutdown.c b/src/net/src/shutdown.c
new file mode 100644
index 0000000..b815e2c
--- /dev/null
+++ b/src/net/src/shutdown.c
@@ -0,0 +1,26 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/types.h>
+#include <wip/wip.h>
+
+int net_shutdown(void)
+{
+ return -1;
+}
diff --git a/src/net/src/update.c b/src/net/src/update.c
new file mode 100644
index 0000000..b7a0954
--- /dev/null
+++ b/src/net/src/update.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <net.h>
+#include <net/types.h>
+#include <wip/wip.h>
+
+int net_update(void)
+{
+ struct net *const n = &net;
+
+ if (!n->init)
+ return 0;
+
+ return wip_run(&n->w) == WIP_FATAL ? -1 : 0;
+}
diff --git a/src/page/CMakeLists.txt b/src/page/CMakeLists.txt
new file mode 100644
index 0000000..2aa2d4c
--- /dev/null
+++ b/src/page/CMakeLists.txt
@@ -0,0 +1,20 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(page)
+add_subdirectory(src)
+target_include_directories(page PUBLIC include PRIVATE private_include)
+target_link_libraries(page PRIVATE kprintf)
diff --git a/src/page/include/page.h b/src/page/include/page.h
new file mode 100644
index 0000000..d5af4be
--- /dev/null
+++ b/src/page/include/page.h
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PAGE_H
+#define PAGE_H
+
+#include <stddef.h>
+
+struct page;
+
+int page_read(struct page **head, unsigned long addr, void *buf, size_t n);
+int page_write(struct page **head, unsigned long addr, const void *buf,
+ size_t n);
+int page_shrink(struct page **head, unsigned long addr);
+
+#endif
diff --git a/src/page/private_include/page/mem.h b/src/page/private_include/page/mem.h
new file mode 100644
index 0000000..abb2c6d
--- /dev/null
+++ b/src/page/private_include/page/mem.h
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PAGE_MEM_H
+#define PAGE_MEM_H
+
+#include <page/types.h>
+#include <stddef.h>
+
+struct page *page_mem_alloc(unsigned long addr);
+
+#endif
diff --git a/src/page/private_include/page/mem/ops.h b/src/page/private_include/page/mem/ops.h
new file mode 100644
index 0000000..5e50256
--- /dev/null
+++ b/src/page/private_include/page/mem/ops.h
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PAGE_MEM_OPS_H
+#define PAGE_MEM_OPS_H
+
+#include <page/types.h>
+
+int page_mem_read(struct page *p, void *buf, size_t n, unsigned long addr);
+int page_mem_write(struct page *p, const void *buf, size_t n, unsigned long addr);
+void page_mem_free(struct page *p);
+
+extern const struct page_ops page_mem_ops;
+
+#endif
diff --git a/src/page/private_include/page/mem/types.h b/src/page/private_include/page/mem/types.h
new file mode 100644
index 0000000..fe0fc74
--- /dev/null
+++ b/src/page/private_include/page/mem/types.h
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PAGE_MEM_TYPES_H
+#define PAGE_MEM_TYPES_H
+
+struct page_prv
+{
+ char buf[256];
+};
+
+#endif
diff --git a/src/page/private_include/page/routines.h b/src/page/private_include/page/routines.h
new file mode 100644
index 0000000..359ca6b
--- /dev/null
+++ b/src/page/private_include/page/routines.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PAGE_ROUTINES_H
+#define PAGE_ROUTINES_H
+
+#include <page.h>
+
+void page_free(struct page *p);
+struct page *page_from_addr(struct page *head, unsigned long addr);
+int page_add(struct page *p, unsigned long addr,
+ struct page *(*alloc)(unsigned long));
+
+#endif
diff --git a/src/page/private_include/page/types.h b/src/page/private_include/page/types.h
new file mode 100644
index 0000000..ae1ff99
--- /dev/null
+++ b/src/page/private_include/page/types.h
@@ -0,0 +1,42 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef PAGE_TYPES_H
+#define PAGE_TYPES_H
+
+#include <stddef.h>
+
+struct page;
+
+struct page_ops
+{
+ int (*read)(struct page *p, void *buf, size_t n, unsigned long addr);
+ int (*write)(struct page *p, const void *buf, size_t n, unsigned long addr);
+ void (*free)(struct page *p);
+};
+
+struct page
+{
+ const struct page_ops *ops;
+ unsigned long addr;
+ size_t sz;
+ struct page_prv *prv;
+ struct page *prev, *next;
+};
+
+#endif
diff --git a/src/page/src/CMakeLists.txt b/src/page/src/CMakeLists.txt
new file mode 100644
index 0000000..9f771b4
--- /dev/null
+++ b/src/page/src/CMakeLists.txt
@@ -0,0 +1,26 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(page PRIVATE
+ add.c
+ free.c
+ from_addr.c
+ read.c
+ shrink.c
+ write.c
+)
+
+add_subdirectory(mem)
diff --git a/src/page/src/add.c b/src/page/src/add.c
new file mode 100644
index 0000000..5ac3c37
--- /dev/null
+++ b/src/page/src/add.c
@@ -0,0 +1,39 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/routines.h>
+#include <page/types.h>
+
+int page_add(struct page *const p, const unsigned long addr,
+ struct page *(*const alloc)(unsigned long))
+{
+ struct page *const np = alloc(addr);
+
+ if (!np)
+ return -1;
+
+ if (p->next)
+ {
+ p->next->prev = np;
+ np->next = p->next;
+ }
+
+ p->next = np;
+ np->prev = p;
+ return 0;
+}
diff --git a/src/page/src/free.c b/src/page/src/free.c
new file mode 100644
index 0000000..f9b72fb
--- /dev/null
+++ b/src/page/src/free.c
@@ -0,0 +1,35 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/routines.h>
+#include <page/types.h>
+#include <stdlib.h>
+
+void page_free(struct page *const p)
+{
+ if (!p)
+ return;
+ else if (p->next)
+ p->next->prev = p->prev;
+
+ if (p->prev)
+ p->prev->next = p->next;
+
+ p->ops->free(p);
+ free(p);
+}
diff --git a/src/page/src/from_addr.c b/src/page/src/from_addr.c
new file mode 100644
index 0000000..8727db6
--- /dev/null
+++ b/src/page/src/from_addr.c
@@ -0,0 +1,30 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/routines.h>
+#include <page/types.h>
+#include <stddef.h>
+
+struct page *page_from_addr(struct page *const head, const unsigned long addr)
+{
+ for (struct page *p = head; p; p = p->next)
+ if (addr >= p->addr && addr < p->addr + p->sz)
+ return p;
+
+ return NULL;
+}
diff --git a/src/page/src/mem/CMakeLists.txt b/src/page/src/mem/CMakeLists.txt
new file mode 100644
index 0000000..ea430c3
--- /dev/null
+++ b/src/page/src/mem/CMakeLists.txt
@@ -0,0 +1,23 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+target_sources(page PRIVATE
+ alloc.c
+ free.c
+ ops.c
+ read.c
+ write.c
+)
diff --git a/src/page/src/mem/alloc.c b/src/page/src/mem/alloc.c
new file mode 100644
index 0000000..be9f43d
--- /dev/null
+++ b/src/page/src/mem/alloc.c
@@ -0,0 +1,50 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/mem.h>
+#include <page/mem/ops.h>
+#include <page/mem/types.h>
+#include <page/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct page *page_mem_alloc(const unsigned long addr)
+{
+ struct page *const ret = malloc(sizeof *ret);
+ struct page_prv *const prv = malloc(sizeof *prv);
+ const unsigned long start = addr - (addr % sizeof prv->buf);
+
+ if (!ret || !prv)
+ goto failure;
+
+ *prv = (const struct page_prv){0};
+ *ret = (const struct page)
+ {
+ .sz = sizeof prv->buf,
+ .ops = &page_mem_ops,
+ .addr = start,
+ .prv = prv
+ };
+
+ return ret;
+
+failure:
+ free(prv);
+ free(ret);
+ return NULL;
+}
diff --git a/src/page/src/mem/free.c b/src/page/src/mem/free.c
new file mode 100644
index 0000000..6834288
--- /dev/null
+++ b/src/page/src/mem/free.c
@@ -0,0 +1,31 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/types.h>
+#include <page/mem/ops.h>
+#include <page/mem/types.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+void page_mem_free(struct page *const p)
+{
+ if (!p->prv)
+ return;
+
+ free(p->prv);
+}
diff --git a/src/page/src/mem/ops.c b/src/page/src/mem/ops.c
new file mode 100644
index 0000000..843b82a
--- /dev/null
+++ b/src/page/src/mem/ops.c
@@ -0,0 +1,27 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/mem/ops.h>
+#include <page/types.h>
+
+const struct page_ops page_mem_ops =
+{
+ .read = page_mem_read,
+ .write = page_mem_write,
+ .free = page_mem_free
+};
diff --git a/src/page/src/mem/read.c b/src/page/src/mem/read.c
new file mode 100644
index 0000000..67d5594
--- /dev/null
+++ b/src/page/src/mem/read.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/types.h>
+#include <page/mem/ops.h>
+#include <page/mem/types.h>
+#include <stddef.h>
+#include <string.h>
+
+int page_mem_read(struct page *const p, void *const buf, const size_t n,
+ const unsigned long addr)
+{
+ const unsigned long offset = addr - p->addr;
+ const char *const src = &p->prv->buf[offset];
+ const size_t rem = p->sz - offset, w = rem < n ? rem : n;
+
+ memcpy(buf, src, w);
+ return w;
+}
diff --git a/src/page/src/mem/write.c b/src/page/src/mem/write.c
new file mode 100644
index 0000000..7cf8f40
--- /dev/null
+++ b/src/page/src/mem/write.c
@@ -0,0 +1,34 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page/types.h>
+#include <page/mem/ops.h>
+#include <page/mem/types.h>
+#include <stddef.h>
+#include <string.h>
+
+int page_mem_write(struct page *const p, const void *const buf, const size_t n,
+ const unsigned long addr)
+{
+ const unsigned long offset = addr - p->addr;
+ char *const dst = &p->prv->buf[offset];
+ const size_t rem = p->sz - offset, w = rem < n ? rem : n;
+
+ memcpy(dst, buf, w);
+ return w;
+}
diff --git a/src/page/src/read.c b/src/page/src/read.c
new file mode 100644
index 0000000..9c50711
--- /dev/null
+++ b/src/page/src/read.c
@@ -0,0 +1,37 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page.h>
+#include <page/routines.h>
+#include <page/types.h>
+#include <page/mem.h>
+
+int page_read(struct page **const head, const unsigned long addr,
+ void *const buf, const size_t n)
+{
+ if (!*head)
+ return (*head = page_mem_alloc(addr)) ? 0 : -1;
+
+ struct page *const p = page_from_addr(*head, addr);
+
+ if (!p)
+ /* TODO: decide best strategy (fs, mem, etc.) */
+ return page_add(*head, addr, page_mem_alloc);
+
+ return p->ops->read(p, buf, n, addr);
+}
diff --git a/src/page/src/shrink.c b/src/page/src/shrink.c
new file mode 100644
index 0000000..53873f6
--- /dev/null
+++ b/src/page/src/shrink.c
@@ -0,0 +1,36 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page.h>
+#include <page/routines.h>
+#include <page/types.h>
+
+int page_shrink(struct page **const head, const unsigned long addr)
+{
+ for (struct page *p = *head; p;)
+ {
+ struct page *const next = p->next;
+
+ if (p->addr > addr)
+ page_free(p);
+
+ p = next;
+ }
+
+ return 0;
+}
diff --git a/src/page/src/write.c b/src/page/src/write.c
new file mode 100644
index 0000000..a28ed2b
--- /dev/null
+++ b/src/page/src/write.c
@@ -0,0 +1,38 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <page.h>
+#include <page/mem.h>
+#include <page/routines.h>
+#include <page/types.h>
+#include <stddef.h>
+
+int page_write(struct page **const head, const unsigned long addr,
+ const void *const buf, const size_t n)
+{
+ if (!*head)
+ return (*head = page_mem_alloc(addr)) ? 0 : -1;
+
+ struct page *const p = page_from_addr(*head, addr);
+
+ if (!p)
+ /* TODO: decide best strategy (fs, mem, etc.) */
+ return page_add(*head, addr, page_mem_alloc);
+
+ return p->ops->write(p, buf, n, addr);
+}
diff --git a/src/ps1/CMakeLists.txt b/src/ps1/CMakeLists.txt
index 6ba4543..0aa710c 100644
--- a/src/ps1/CMakeLists.txt
+++ b/src/ps1/CMakeLists.txt
@@ -1,5 +1,37 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
target_link_libraries(${PROJECT_NAME} PRIVATE c)
target_link_libraries(nanowasm PRIVATE c)
+target_link_libraries(wip PRIVATE c)
+target_link_libraries(dynstr PRIVATE c)
target_sources(${PROJECT_NAME} PRIVATE start.c)
target_link_options(${PROJECT_NAME} PRIVATE
-T${CMAKE_CURRENT_LIST_DIR}/playstation.x)
+add_custom_target(system_cnf ALL
+ ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_LIST_DIR}/system.cnf ${CMAKE_BINARY_DIR}
+)
+add_custom_target(mkpsxiso_xml ALL
+ ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_LIST_DIR}/wnix.xml ${CMAKE_BINARY_DIR}
+)
+add_custom_target(license ALL
+ ${CMAKE_COMMAND} -E copy_if_different
+ ${CMAKE_CURRENT_LIST_DIR}/infoeur.dat ${CMAKE_BINARY_DIR}
+)
+add_dependencies(mkpsxiso_xml system_cnf license ${PROJECT_NAME})
+add_dependencies(bin_cue mkpsxiso_xml)
diff --git a/src/ps1/playstation.x b/src/ps1/playstation.x
index 00a1a74..71a4c34 100644
--- a/src/ps1/playstation.x
+++ b/src/ps1/playstation.x
@@ -68,5 +68,7 @@ SECTIONS
__bss_start = ADDR(.bss);
__bss_end = ADDR(.bss) + SIZEOF(.bss);
+ __ram_end = 0x8020FFFF;
+
__scratchpad = 0x1f800000;
}
diff --git a/src/ps1/start.c b/src/ps1/start.c
index 09ca6c9..c5558fe 100644
--- a/src/ps1/start.c
+++ b/src/ps1/start.c
@@ -1,7 +1,7 @@
__attribute__((__section__(".text.startup"))) void _start(void)
{
int main(void);
- extern char *__bss_start, *__bss_end;
+ extern char __bss_start[], __bss_end[];
for (char *s = __bss_start; s < __bss_end; s++)
*s = 0;
diff --git a/src/ps1/system.cnf b/src/ps1/system.cnf
index 1c3aebe..8c30bfa 100644
--- a/src/ps1/system.cnf
+++ b/src/ps1/system.cnf
@@ -1,4 +1,4 @@
-BOOT = cdrom:\wanix.exe;1
-TCB = 1
-EVENT = 8
-STACK = 801FF800
+BOOT = cdrom:\wnix.exe;1
+TCB = 1
+EVENT = 10
+STACK = 801FF800
diff --git a/src/ps1/wnix.xml b/src/ps1/wnix.xml
new file mode 100644
index 0000000..b7a695e
--- /dev/null
+++ b/src/ps1/wnix.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<iso_project image_name="wnix.bin" cue_sheet="wnix.cue" no_xa="0">
+ <track type="data">
+ <identifiers
+ volume = "WNIX"
+ volume_set = "WNIX"
+ publisher = "WNIX"
+ />
+ <license file="infoeur.dat"/>
+ <directory_tree>
+ <file name="system.cnf" source="system.cnf"/>
+ <file name="wnix.exe" source="wnix.exe"/>
+ <dir name="bin" source="bin">
+ <file name="initd" source="bin/initd"/>
+ <file name="yes" source="bin/yes"/>
+ </dir>
+ <dummy sectors="13500" type="0"/>
+ </directory_tree>
+ </track>
+</iso_project>
diff --git a/src/state/CMakeLists.txt b/src/state/CMakeLists.txt
new file mode 100644
index 0000000..ef2c6db
--- /dev/null
+++ b/src/state/CMakeLists.txt
@@ -0,0 +1,18 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+add_library(state INTERFACE)
+target_include_directories(state INTERFACE include)
diff --git a/src/state/include/state.h b/src/state/include/state.h
new file mode 100644
index 0000000..cd78dae
--- /dev/null
+++ b/src/state/include/state.h
@@ -0,0 +1,29 @@
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef STATE_H
+#define STATE_H
+
+enum state
+{
+ STATE_OK,
+ STATE_AGAIN,
+ STATE_FATAL
+};
+
+#endif
diff --git a/src/wip b/src/wip
-Subproject f103800ac4d766c261a99a580c20a2447610152
+Subproject c11cb04929f28853142b14339b66f561ca028f3
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index afb5355..682781f 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,9 +1,38 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
cmake_minimum_required(VERSION 3.13)
-project(utils)
+project(tools)
+set(MKPSXISO_NO_LIBFLAC ON)
add_subdirectory(mkpsxiso)
-add_executable(container "container.c")
-add_executable(add-header "add-header.c")
+add_subdirectory(nwc)
+add_executable(container container.c)
+add_executable(add-header add-header.c)
+add_executable(elf2exe elf2exe.c)
set(cflags -Wall -g3)
target_compile_options(container PUBLIC ${cflags})
target_compile_options(add-header PUBLIC ${cflags})
-install(TARGETS container add-header DESTINATION bin)
+target_compile_options(elf2exe PUBLIC ${cflags})
+target_compile_definitions(elf2exe
+ PRIVATE OBJCOPY_PATH=\"mipsel-unknown-elf-objcopy\")
+install(TARGETS container add-header elf2exe nwc DESTINATION bin)
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ add_subdirectory(tun2tcp)
+else()
+ message(STATUS "CMAKE_SYSTEM_NAME (${CMAKE_SYSTEM_NAME}) is not Linux, "
+ "skipping tun2tcp")
+endif()
diff --git a/tools/elf2exe.c b/tools/elf2exe.c
new file mode 100755
index 0000000..8ce3702
--- /dev/null
+++ b/tools/elf2exe.c
@@ -0,0 +1,250 @@
+/*
+ * Original source code from PSXSDK, by Giuseppe Gata.
+ * Released under a weak copyleft-like license, pasted below:
+ *
+ * You can use this library for any project, commercial and non-commercial,
+ * open-source and closed-source. But if you modify the library, you must
+ * redistribute the source for the modifications you did to it.
+ * Not doing that constitutes an infringement of this license.
+ * You are not obliged to redistribute the source code of this library if it
+ * was not modified at all by you or anyone related to you.
+ *
+ * There is no advertising clause; you aren't obliged to mention this library
+ * in any documentation of your work using it; however, it would be a nice gesture
+ * if you did so.
+ *
+ * These terms were written to not make people close this work which was released
+ * for all to share. In fact, no use is otherwise restricted.
+ */
+
+/*
+ * elf2exe
+ *
+ * Converts an ELF executable to PS-EXE, using objcopy
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const unsigned char psexe_magic[8] = {'P','S','-','X',' ','E','X','E'};
+const char *psexe_marker_usa = "Sony Computer Entertainment Inc. for North America area";
+const char *psexe_marker_jpn = "Sony Computer Entertainment Inc. for Japan area";
+const char *psexe_marker_eur = "Sony Computer Entertainment Inc. for Europe area";
+char *psexe_marker;
+
+//#define OBJCOPY_PATH "mipsel-unknown-elf-objcopy"
+
+int main(int argc, char *argv[])
+{
+ FILE *objcopy_out, *psexe;
+ char stringbuf[2048];
+ unsigned char charbuf;
+ int x;
+ unsigned int sz;
+ unsigned int gp = 0;
+
+ if(argc < 3)
+ {
+ printf("elf2exe - Converts an ELF executable to PS-EXE\n");
+ printf("usage: elf2exe [elf] [ps-x exe] <options>\n");
+ printf("\n");
+ printf("Options:\n");
+ printf("-mark_jpn - Use Japanese ascii marker (default: USA)\n");
+ printf("-mark_eur - Use European ascii marker (default: USA)\n");
+ printf("-mark=<mark> - Use custom ascii marker <mark>\n");
+ return -1;
+ }
+
+ psexe_marker = (char*)psexe_marker_usa;
+
+ for(x = 3; x < argc; x++)
+ {
+ if(strcmp(argv[x], "-mark_jpn") == 0)
+ psexe_marker = (char*)psexe_marker_jpn;
+
+ if(strcmp(argv[x], "-mark_eur") == 0)
+ psexe_marker = (char*)psexe_marker_eur;
+
+ if(strncmp(argv[x], "-mark=", 6) == 0)
+ {
+ if(strlen(argv[x]) >= 7)
+ psexe_marker = argv[x] + 6;
+ }
+
+ if(strncmp(argv[x], "-gp=", 4) == 0)
+ {
+ if(strlen(argv[x]) >= 5)
+ sscanf(argv[x] + 4, "%x", &gp);
+ }
+ }
+
+/*
+ * Now open the output file
+ */
+
+ psexe = fopen(argv[2], "wb");
+
+ if(psexe == NULL)
+ {
+ printf("Couldn't open %s for writing. Aborting!\n", argv[2]);
+ return -1;
+ }
+
+/*
+ * Write PSEXE magic string
+ */
+ fwrite(psexe_magic, sizeof(char), 8, psexe);
+
+/*
+ * Seek output file to 0x10, Initial Program Counter
+ */
+ fseek(psexe, 0x10, SEEK_SET);
+
+/*
+ * Write initial program counter = 0x80010000
+ */
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x01;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Global Pointer
+ */
+ charbuf = gp & 0xff;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff00) >> 8;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff0000) >> 16;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (gp & 0xff000000) >> 24;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Seek output file to 0x18, Text section start address
+ */
+ fseek(psexe, 0x18, SEEK_SET);
+
+/*
+ * Write text section start address = 0
+ */
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x00;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x01;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+/*
+ * Seek output file to 0x30, Initial Stack Pointer
+ */
+ fseek(psexe, 0x30, SEEK_SET);
+
+/*
+ * Write Initial Stack Pointer = 0x801FFFF0
+ */
+ charbuf = 0xF0;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0xFF;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x1F;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = 0x80;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+
+/*
+ * Seek output to 0x4C, ASCII marker
+ */
+ fseek(psexe, 0x4C, SEEK_SET);
+
+ x = 0;
+
+/*
+ * Write ASCII marker string
+ */
+ while(psexe_marker[x])
+ fwrite(&psexe_marker[x++], sizeof(char), 1, psexe);
+
+/*
+ * Run objcopy now
+ */
+ sprintf(stringbuf, OBJCOPY_PATH" -O binary %s %s.bin", argv[1], argv[1]);
+ system(stringbuf);
+
+ sprintf(stringbuf, "%s.bin", argv[1]);
+
+/*
+ * Open objcopy output
+ */
+
+ objcopy_out = fopen(stringbuf, "rb");
+ if(objcopy_out == NULL)
+ {
+ printf("Could not open objcopy output at %s. Check your permissions. Aborting.\n",
+ stringbuf);
+ return -1;
+ }
+
+/*
+ * Seek to 0x800, Program Start
+ * and write the output of objcopy into the PS-X EXE
+ */
+ fseek(psexe, 0x800, SEEK_SET);
+
+ while(!feof(objcopy_out))
+ {
+ x = fgetc(objcopy_out);
+ fputc(x, psexe);
+ }
+
+
+ fclose(objcopy_out);
+
+/*
+ * Get the file size of the PS-X EXE
+ */
+ fseek(psexe, 0, SEEK_END);
+ sz = ftell(psexe);
+ fseek(psexe, 0, SEEK_SET);
+
+ if(sz % 2048 != 0)
+ {
+ fseek(psexe, (((sz / 2048) + 1)*2048) - 1, SEEK_SET);
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ sz = ftell(psexe);
+ }
+
+/*
+ * Write the address of the text section in the header of the PS-X EXE
+ */
+
+ sz -= 0x800;
+
+ fseek(psexe, 0x1C, SEEK_SET);
+
+ charbuf = sz & 0xff;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff00) >> 8;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff0000) >> 16;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+ charbuf = (sz & 0xff000000) >> 24;
+ fwrite(&charbuf, sizeof(char), 1, psexe);
+
+ fclose(psexe);
+
+/*
+ * Remove objcopy output
+ */
+ sprintf(stringbuf, "%s.bin", argv[1]);
+ remove(stringbuf);
+
+ return 0;
+}
diff --git a/tools/nwc b/tools/nwc
-Subproject 1a9ca72b3b88054403995ce71887d09052f4ef4
+Subproject 15d2bb51e092d6dc34fa5fb5c1eb9b64c7c597b
diff --git a/tools/tun2tcp/CMakeLists.txt b/tools/tun2tcp/CMakeLists.txt
new file mode 100644
index 0000000..674aef6
--- /dev/null
+++ b/tools/tun2tcp/CMakeLists.txt
@@ -0,0 +1,21 @@
+# wnix, a Unix-like operating system for WebAssembly applications.
+# Copyright (C) 2025 Xavier Del Campo Romero
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+cmake_minimum_required(VERSION 3.13)
+project(tun2tcp C)
+add_executable(${PROJECT_NAME} tun2tcp.c)
+target_compile_options(${PROJECT_NAME} PUBLIC ${cflags})
+install(TARGETS ${PROJECT_NAME} DESTINATION bin)
diff --git a/tools/tun2tcp/README.md b/tools/tun2tcp/README.md
new file mode 100644
index 0000000..9fcc641
--- /dev/null
+++ b/tools/tun2tcp/README.md
@@ -0,0 +1,13 @@
+# tun2serial
+
+```sh
+# setcap cap_net_admin+ep ./tun2serial
+# sudo ip addr add 10.0.0.1/24 dev tun0
+# sudo ip link set tun0 up
+# socat TCP-L:6699 /dev/ttyUSB0,rawer,b1200
+```
+
+## Thanks
+
+- https://backreference.org/2010/03/26/tuntap-interface-tutorial/index.html
+- https://blog.mbedded.ninja/programming/operating-systems/linux/linux-serial-ports-using-c-cpp/
diff --git a/tools/tun2tcp/tun2tcp.c b/tools/tun2tcp/tun2tcp.c
new file mode 100644
index 0000000..4b6615f
--- /dev/null
+++ b/tools/tun2tcp/tun2tcp.c
@@ -0,0 +1,160 @@
+
+/*
+ * wnix, a Unix-like operating system for WebAssembly applications.
+ * Copyright (C) 2025 Xavier Del Campo Romero
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <net/if.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static int getport(const char *const s, unsigned short *const port)
+{
+ char *end;
+ unsigned long v;
+
+ errno = 0;
+ v = strtoull(s, &end, 10);
+
+ if (errno || *end || v > USHRT_MAX)
+ return -1;
+
+ *port = v;
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ static const char path[] = "/dev/net/tun";
+ char *s = NULL;
+ int ret = EXIT_FAILURE, cfd = -1, tfd = -1;
+ unsigned short port;
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "%s <port>\n", *argv);
+ goto end;
+ }
+ else if (getport(argv[1], &port))
+ {
+ fprintf(stderr, "invalid port: %s\n", argv[1]);
+ goto end;
+ }
+ else if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ perror("socket(2)");
+ goto end;
+ }
+
+ const struct sockaddr_in addr =
+ {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = inet_addr("127.0.0.1"),
+ .sin_port = htons(port)
+ };
+
+ const struct ifreq ifr = {.ifr_flags = IFF_TUN | IFF_NO_PI};
+
+ if (connect(cfd, (const struct sockaddr *)&addr, sizeof addr))
+ {
+ perror("connect(2)");
+ goto end;
+ }
+ else if ((tfd = open(path, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "open(2) %s: %s\n", path, strerror(errno));
+ goto end;
+ }
+ else if (ioctl(tfd, TUNSETIFF, &ifr) < 0)
+ {
+ perror("ioctl(2)");
+ goto end;
+ }
+ else if (!(s = strdup(ifr.ifr_name)))
+ {
+ perror("strdup(3)");
+ goto end;
+ }
+
+ fprintf(stderr, "set up TUN device %s\n", s);
+ unsigned long long total = 0;
+
+ for (;;)
+ {
+ char b[1500];
+ ssize_t n = read(tfd, &b, sizeof b);
+
+ if (n < 0)
+ {
+ perror("read(2)");
+ goto end;
+ }
+
+ fprintf(stderr, "read %zu bytes\n", n);
+
+ size_t rem = n;
+
+ while (rem)
+ {
+ const void *p = b;
+
+ fprintf(stderr, "sending %zu bytes\n", rem);
+
+ if ((n = write(cfd, p, rem)) < 0)
+ {
+ perror("write(2)");
+ goto end;
+ }
+
+ fprintf(stderr, "sent %zu bytes, total: %llu\n", n, total += n);
+
+ p = (const char *)p + n;
+ rem -= n;
+ }
+ }
+
+ ret = EXIT_SUCCESS;
+
+end:
+
+ if (cfd >= 0 && close(cfd))
+ {
+ ret = EXIT_FAILURE;
+ perror("close(2)");
+ }
+
+ if (tfd >= 0 && close(tfd))
+ {
+ ret = EXIT_FAILURE;
+ fprintf(stderr, "close(2) %s: %s\n", path, strerror(errno));
+ }
+
+ free(s);
+ return ret;
+}