diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-07-07 13:22:53 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-11-11 00:08:15 +0100 |
| commit | 7861a52adf92a083bb2aed4c35f98d8035dce032 (patch) | |
| tree | 28cd3c40e4c878f730f5df3c1d93bdf91af490c3 /src/bin | |
| parent | 7fc48e9216ff809da5f8055a50b0be17628ef1df (diff) | |
| download | wnix-7861a52adf92a083bb2aed4c35f98d8035dce032.tar.gz | |
Setup project skeleton
Diffstat (limited to 'src/bin')
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; +} |
