aboutsummaryrefslogtreecommitdiff
path: root/src/bin
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 /src/bin
parent7fc48e9216ff809da5f8055a50b0be17628ef1df (diff)
downloadwnix-7861a52adf92a083bb2aed4c35f98d8035dce032.tar.gz
Setup project skeleton
Diffstat (limited to 'src/bin')
-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
63 files changed, 4038 insertions, 0 deletions
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;
+}