summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/include/arch/aarch64/param.h35
-rw-r--r--sys/include/arch/amd64/param.h35
-rw-r--r--sys/include/net/netbuf.h2
-rw-r--r--sys/include/sys/limits.h3
-rw-r--r--sys/include/sys/param.h10
-rw-r--r--sys/include/sys/proc.h3
-rw-r--r--sys/include/sys/socket.h97
-rw-r--r--sys/include/sys/socketvar.h53
-rw-r--r--sys/include/sys/syscall.h4
-rw-r--r--sys/include/sys/uio.h51
-rw-r--r--sys/include/sys/vnode.h1
-rw-r--r--sys/include/sys/vsr.h165
-rw-r--r--sys/kern/kern_socket.c447
-rw-r--r--sys/kern/kern_syscall.c5
-rw-r--r--sys/kern/kern_uio.c156
-rw-r--r--sys/kern/kern_vsr.c344
16 files changed, 1411 insertions, 0 deletions
diff --git a/sys/include/arch/aarch64/param.h b/sys/include/arch/aarch64/param.h
new file mode 100644
index 0000000..c074ffb
--- /dev/null
+++ b/sys/include/arch/aarch64/param.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _AARCH64_PARAM_H_
+#define _AARCH64_PARAM_H_
+
+#define M_WORD_SIZE 4
+
+#endif /* !_AARCH64_PARAM_H_ */
diff --git a/sys/include/arch/amd64/param.h b/sys/include/arch/amd64/param.h
new file mode 100644
index 0000000..6ea3fca
--- /dev/null
+++ b/sys/include/arch/amd64/param.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _AMD64_PARAM_H_
+#define _AMD64_PARAM_H_
+
+#define M_WORD_SIZE 8
+
+#endif /* !_AMD64_PARAM_H_ */
diff --git a/sys/include/net/netbuf.h b/sys/include/net/netbuf.h
index 33ba06f..7067370 100644
--- a/sys/include/net/netbuf.h
+++ b/sys/include/net/netbuf.h
@@ -30,6 +30,8 @@
#ifndef _NET_NETBUF_H_
#define _NET_NETBUF_H_
+#include <sys/types.h>
+
#define NETBUF_LEN 256
struct netbuf {
diff --git a/sys/include/sys/limits.h b/sys/include/sys/limits.h
index f6aed9d..c0ce5af 100644
--- a/sys/include/sys/limits.h
+++ b/sys/include/sys/limits.h
@@ -36,4 +36,7 @@
#define ARG_MAX 4096
#define CHAR_BIT 8
#define CPU_MAX 256
+#define VSR_MAX_DOMAIN 16
+#define VSR_MAX_CAPSULE 16
+#define IOVEC_MAX 512
#endif /* !_SYS_LIMITS_H_ */
diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h
index 7331d5f..2bbbabd 100644
--- a/sys/include/sys/param.h
+++ b/sys/include/sys/param.h
@@ -30,11 +30,20 @@
#ifndef _SYS_PARAM_H_
#define _SYS_PARAM_H_
+#if defined(_KERNEL)
+#include <machine/param.h>
+#endif
+
/* Assumed cache line size */
#ifndef COHERENCY_UNIT
#define COHERENCY_UNIT 64
#endif
+/* Assumed machine word size */
+#ifndef M_WORD_SIZE
+#define M_WORD_SIZE 4
+#endif
+
/* Bit related macros */
#define ISSET(v, f) ((v) & (f))
#define BIT(n) (1ULL << (n))
@@ -47,6 +56,7 @@
/* Align up/down a value */
#define ALIGN_DOWN(value, align) ((value) & ~((align)-1))
#define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1))
+#define MALIGN(value) ALIGN_UP((value), M_WORD_SIZE)
/* Bitmap helper macros */
#define setbit(a, b) ((a)[(b) >> 3] |= BIT(b % 8))
diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h
index 9cc9238..89fe638 100644
--- a/sys/include/sys/proc.h
+++ b/sys/include/sys/proc.h
@@ -39,6 +39,8 @@
#include <sys/syscall.h>
#include <sys/exec.h>
#include <sys/ucred.h>
+#include <sys/limits.h>
+#include <sys/vsr.h>
#include <sys/filedesc.h>
#include <sys/signal.h>
#include <sys/vnode.h>
@@ -88,6 +90,7 @@ struct proc {
struct ucred cred;
struct ksiginfo *ksig_list[PROC_SIGMAX];
struct filedesc *fds[PROC_MAX_FILEDES];
+ struct vsr_domain *vsr_tab[VSR_MAX_DOMAIN];
struct mmap_lgdr *mlgdr;
struct vcache *vcache;
struct spinlock vcache_lock;
diff --git a/sys/include/sys/socket.h b/sys/include/sys/socket.h
new file mode 100644
index 0000000..f01e2bf
--- /dev/null
+++ b/sys/include/sys/socket.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_SOCKET_H_
+#define _SYS_SOCKET_H_
+
+#include <sys/socketvar.h>
+#if defined(_KERNEL)
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/mutex.h>
+#else
+#include <stdint.h>
+#include <stddef.h>
+#endif /* _KERNEL */
+
+#ifndef _SA_FAMILY_T_DEFINED_
+#define _SA_FAMILY_T_DEFINED_
+typedef uint32_t sa_family_t;
+#endif /* _SA_FAMILY_T_DEFINED_ */
+
+#ifndef _SOCKLEN_T_DEFINED_
+#define _SOCKLEN_T_DEFINED_
+typedef uint32_t socklen_t;
+#endif /* !_SOCKLEN_T_DEFINED_ */
+
+/*
+ * Address family defines
+ */
+#define AF_UNSPEC 0
+#define AF_UNIX 1
+#define AF_LOCAL AF_UNIX
+
+/* Socket types */
+#define SOCK_STREAM 1
+
+struct sockaddr_un {
+ sa_family_t sun_family;
+ char sun_path[108];
+};
+
+struct sockaddr {
+ sa_family_t sa_family;
+ char sa_data[14];
+};
+
+#if defined(_KERNEL)
+
+struct ksocket {
+ int sockfd;
+ union {
+ struct sockaddr sockaddr;
+ struct sockaddr_un un;
+ };
+ struct sockbuf buf;
+ struct mutex *mtx;
+};
+
+scret_t sys_socket(struct syscall_args *scargs);
+scret_t sys_bind(struct syscall_args *scargs);
+scret_t sys_recv(struct syscall_args *scargs);
+scret_t sys_send(struct syscall_args *scargs);
+#endif /* _KERNEL */
+
+int socket(int domain, int type, int protocol);
+int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
+
+ssize_t send(int sockfd, const void *buf, size_t size, int flags);
+ssize_t recv(int sockfd, void *buf, size_t len, int flags);
+
+#endif /* !_SYS_SOCKET_H_ */
diff --git a/sys/include/sys/socketvar.h b/sys/include/sys/socketvar.h
new file mode 100644
index 0000000..e090a70
--- /dev/null
+++ b/sys/include/sys/socketvar.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_SOCKETVAR_H_
+#define _SYS_SOCKETVAR_H_
+
+#include <sys/types.h>
+#if defined(_KERNEL)
+#include <net/netbuf.h>
+
+/*
+ * Socket buffer
+ *
+ * @buf: Actual data buffer
+ * @head: Buffer head
+ * @tail: Buffer tail
+ * @watermark: Max length
+ */
+struct sockbuf {
+ struct netbuf buf;
+ size_t head;
+ size_t tail;
+ size_t watermark;
+};
+
+#endif /* _KERNEL */
+#endif /* !_SYS_SOCKETVAR_H_ */
diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h
index 02629a9..51a1016 100644
--- a/sys/include/sys/syscall.h
+++ b/sys/include/sys/syscall.h
@@ -59,6 +59,10 @@
#define SYS_setuid 18
#define SYS_getuid 19
#define SYS_waitpid 20
+#define SYS_socket 21
+#define SYS_bind 22
+#define SYS_recv 23
+#define SYS_send 24
#if defined(_KERNEL)
/* Syscall return value and arg type */
diff --git a/sys/include/sys/uio.h b/sys/include/sys/uio.h
new file mode 100644
index 0000000..d1d4c65
--- /dev/null
+++ b/sys/include/sys/uio.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_UIO_H_
+#define _SYS_UIO_H_
+
+#if defined(_KERNEL)
+#include <sys/types.h>
+#else
+#include <stdint.h>
+#include <stddef.h>
+#endif /* _KERNEL */
+
+/*
+ * POSIX I/O vector
+ */
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
+ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);
+ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);
+
+#endif /* !_SYS_UIO_H_ */
diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h
index 3402b02..ff6f995 100644
--- a/sys/include/sys/vnode.h
+++ b/sys/include/sys/vnode.h
@@ -76,6 +76,7 @@ struct vcache {
#define VDIR 0x02 /* Directory */
#define VCHR 0x03 /* Character device */
#define VBLK 0x04 /* Block device */
+#define VSOCK 0x05 /* Socket */
#define VNOVAL -1
diff --git a/sys/include/sys/vsr.h b/sys/include/sys/vsr.h
new file mode 100644
index 0000000..e63cce1
--- /dev/null
+++ b/sys/include/sys/vsr.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_VSR_H_
+#define _SYS_VSR_H_
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/limits.h>
+#if defined(_KERNEL)
+#include <sys/mutex.h>
+#endif /* _KERNEL */
+
+struct proc;
+
+#define VSR_FILE 0x00000000 /* Represented by file */
+
+/*
+ * Defines the access semantics of whether
+ * r/w operations should be passed down to the
+ * global state or soley affecting a per-process
+ * shallow copy.
+ */
+typedef uint32_t vsr_mode_t;
+
+/*
+ * The Virtual System Resource namespace consists of
+ * domains containing named "capsules". The domain is
+ * simply a table indexed by a type value e.g. VSR_FILE
+ * and a capsule is simply a structure containing global data
+ * as well as a shallow copy which is controlled locally by the
+ * process. The capsule also contains various access semantics
+ * that help the VSR subsystem determine whether the access should
+ * be passed down globally or virtualized locally within the process.
+ */
+typedef uint8_t vsr_domain_t;
+
+/*
+ * VSR mode bits
+ */
+#define VSR_GLOB_WRITE BIT(0) /* Writes are global */
+#define VSR_GLOB_READ BIT(1) /* Reads are global */
+#define VSR_GLOB_CRED BIT(2) /* Global for specific creds */
+
+#if defined(_KERNEL)
+
+struct vsr_capsule;
+
+/*
+ * VSR capsule operations
+ *
+ * @reclaim: Cleanup resources
+ */
+struct capsule_ops {
+ int(*reclaim)(struct vsr_capsule *cap, int flags);
+};
+
+/*
+ * Virtual system resource access
+ * semantics.
+ *
+ * @glob: Global data
+ * @shallow: Local per process copy
+ * @mode: VSR mode (see VSR_GLOB_*)
+ * @cred: Creds (used if VSR_GLOBAL_CRED set)
+ */
+struct vsr_access {
+ void *glob;
+ void *shallow;
+ vsr_mode_t mode;
+ struct ucred cred;
+};
+
+/*
+ * A virtual system resource capsule containing
+ * resource owner specific data and hashmap
+ * buckets.
+ *
+ * @name: Capsule name (e.g., "consfeat"), must be freed
+ * @data: Owner specific data
+ * @shadow: Local shadow copy (per-process)
+ * @buckets: Hashmap buckets
+ * @link: Bucket link
+ * @ops: Capsule operations
+ * @lock: Mutex lock protecting fields
+ */
+struct vsr_capsule {
+ char *name;
+ void *data;
+ void *shadow;
+ TAILQ_HEAD(, vsr_capsule) buckets;
+ TAILQ_ENTRY(vsr_capsule) link;
+ struct capsule_ops ops;
+ struct mutex lock;
+};
+
+/*
+ * Virtual system resource table containg
+ * VSRs for various types.
+ *
+ * Each VSR table belongs to a VSR domain
+ * (e.g., VSR_FILE).
+ *
+ * @ncaps: Number of capsules
+ * @is_init: Set if hashmap is set up
+ * @capsules: VSR capsule hashmap
+ */
+struct vsr_table {
+ struct vsr_capsule *capsules[VSR_MAX_CAPSULE];
+};
+
+/*
+ * Virtual system resource domain (VSR).
+ *
+ * A VSR is represented by a specific VSR type
+ * (see VSR_*). Each VSR has a table of VSR capsules
+ * looked up by a VSR capsule name.
+ *
+ * One per process.
+ *
+ * @type: VSR type
+ * @table: VSR table
+ */
+struct vsr_domain {
+ int type;
+ struct vsr_table table;
+};
+
+void vsr_init_domains(struct proc *td);
+void vsr_destroy_domains(struct proc *td);
+
+struct vsr_domain *vsr_new_domain(struct proc *td, vsr_domain_t type);
+struct vsr_capsule *vsr_new_capsule(struct proc *td, vsr_domain_t type, const char *name);
+struct vsr_capsule *vsr_lookup_capsule(struct proc *td, vsr_domain_t type, const char *name);
+
+#endif /* _KERNEL */
+#endif /* !_SYS_VSR_H_ */
diff --git a/sys/kern/kern_socket.c b/sys/kern/kern_socket.c
new file mode 100644
index 0000000..a6cc8d2
--- /dev/null
+++ b/sys/kern/kern_socket.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/socket.h>
+#include <sys/sio.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/filedesc.h>
+#include <sys/vnode.h>
+#include <vm/dynalloc.h>
+#include <string.h>
+
+#define pr_trace(fmt, ...) kprintf("socket: " fmt, ##__VA_ARGS__)
+#define pr_error(...) pr_trace(__VA_ARGS__)
+
+static struct vops socket_vops;
+
+/*
+ * Get a kernel socket structure from a
+ * file descriptor.
+ *
+ * @sockfd: File descriptor to lookup
+ * @res: Result pointer
+ *
+ * Returns zero on success, otherwise a less
+ * than zero errno.
+ */
+static int
+get_ksock(int sockfd, struct ksocket **res)
+{
+ struct ksocket *ksock;
+ struct filedesc *fdesc;
+ struct vnode *vp;
+
+ if (res == NULL) {
+ return -EINVAL;
+ }
+
+ /* Grab the file descriptor */
+ fdesc = fd_get(sockfd);
+ if (fdesc == NULL) {
+ return -EBADF;
+ }
+
+ /* Is this even a socket? */
+ if ((vp = fdesc->vp) == NULL) {
+ return -ENOTSOCK;
+ }
+ if (vp->type != VSOCK) {
+ return -ENOTSOCK;
+ }
+
+ ksock = vp->data;
+ if (__unlikely(ksock == NULL)) {
+ return -EIO;
+ }
+
+ *res = ksock;
+ return 0;
+}
+
+/*
+ * VFS reclaim callback for the socket
+ * layer
+ *
+ * Returns zero on success, otherwise a less
+ * than zero errno.
+ */
+static int
+socket_reclaim(struct vnode *vp)
+{
+ struct ksocket *ksock;
+
+ /* Is this even a socket? */
+ if (vp->type != VSOCK) {
+ return -ENOTSOCK;
+ }
+
+ /* Is there any data attached? */
+ if ((ksock = vp->data) == NULL) {
+ return -EIO;
+ }
+
+ fd_close(ksock->sockfd);
+ mutex_free(ksock->mtx);
+ dynfree(ksock);
+ return 0;
+}
+
+/*
+ * Send data to socket - POSIX send(2) core
+ *
+ * @sockfd: File descriptor that backs this socket
+ * @buf: Buffer containing data to transmit
+ * @size: Size of the buffer
+ * @flags: Optional flags
+ *
+ * Returns zero on success, otherwise a less
+ * than zero errno.
+ */
+ssize_t
+send(int sockfd, const void *buf, size_t size, int flags)
+{
+ struct ksocket *ksock;
+ struct sockbuf *sbuf;
+ struct netbuf *netbuf;
+ size_t tail;
+ int error;
+
+ /* Size cannot be zero */
+ if (size == 0) {
+ return -EINVAL;
+ }
+
+ if ((error = get_ksock(sockfd, &ksock)) < 0) {
+ return error;
+ }
+
+ sbuf = &ksock->buf;
+ netbuf = &sbuf->buf;
+ mutex_acquire(ksock->mtx, 0);
+
+ /* Make sure we dont overflow */
+ if (netbuf->len > sbuf->watermark) {
+ mutex_release(ksock->mtx);
+ return -ENOBUFS;
+ }
+
+ if (netbuf->len == 0) {
+ sbuf->head = 0;
+ sbuf->tail = 0;
+ }
+
+ /* Clamp the size if needed */
+ if ((netbuf->len + size) > sbuf->watermark) {
+ size = sbuf->watermark - netbuf->len;
+ }
+ if (size == 0) {
+ return -ENOBUFS;
+ }
+
+ /* Copy the new data */
+ tail = sbuf->tail;
+ memcpy(&netbuf->data[tail], buf, size);
+
+ sbuf->tail += size;
+ netbuf->len += size;
+ mutex_release(ksock->mtx);
+ return size;
+}
+
+/*
+ * Recv data from socket - POSIX recv(2) core
+ *
+ * @sockfd: File descriptor that backs this socket
+ * @buf: RX buffer
+ * @size: Size of the buffer
+ * @flags: Optional flags
+ *
+ * Returns zero on success, otherwise a less
+ * than zero errno.
+ */
+ssize_t
+recv(int sockfd, void *buf, size_t len, int flags)
+{
+ struct ksocket *ksock;
+ struct sockbuf *sbuf;
+ struct netbuf *netbuf;
+ size_t head;
+ int error;
+
+ /* Length cannot be zero */
+ if (len == 0) {
+ return -EINVAL;
+ }
+
+ if ((error = get_ksock(sockfd, &ksock)) < 0) {
+ return error;
+ }
+
+ sbuf = &ksock->buf;
+ netbuf = &sbuf->buf;
+ mutex_acquire(ksock->mtx, 0);
+
+ /* Is it empty? */
+ if (netbuf->len == 0) {
+ sbuf->head = 0;
+ sbuf->tail = 0;
+ return -EAGAIN;
+ }
+
+ if (len > netbuf->len) {
+ len = netbuf->len;
+ }
+
+ head = sbuf->head;
+ memcpy(buf, &netbuf->data[head], len);
+
+ sbuf->head = (sbuf->head + len) % NETBUF_LEN;
+ mutex_release(ksock->mtx);
+ return len;
+}
+
+/*
+ * POSIX socket(7) core
+ *
+ * @domain: Address family (see AF_*)
+ * @type: Socket type
+ * @protocol: Socket protocol
+ *
+ * Returns zero on success, otherwise a less
+ * than zero errno.
+ */
+int
+socket(int domain, int type, int protocol)
+{
+ struct vnode *vp = NULL;
+ struct ksocket *ksock = NULL;
+ struct filedesc *fdesc = NULL;
+ struct sockbuf *sbuf = NULL;
+ int fd, error = -1;
+
+ if ((error = fd_alloc(&fdesc)) < 0) {
+ return error;
+ }
+
+ fd = fdesc->fdno;
+
+ /* Grab a new socket vnode */
+ if ((error = vfs_alloc_vnode(&vp, VSOCK)) < 0) {
+ fd_close(fd);
+ return error;
+ }
+
+ if (vp == NULL) {
+ error = -ENOBUFS;
+ goto fail;
+ }
+
+ ksock = dynalloc(sizeof(*ksock));
+ if (ksock == NULL) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ fdesc->vp = vp;
+ vp->vops = &socket_vops;
+
+ sbuf = &ksock->buf;
+ sbuf->head = 0;
+ sbuf->tail = 0;
+
+ switch (domain) {
+ case AF_UNIX:
+ {
+ struct sockaddr_un *un;
+
+ un = &ksock->un;
+ sbuf->watermark = NETBUF_LEN;
+
+ /*
+ * XXX: We could allow actual paths within the
+ * file system for sockets.
+ */
+ un->sun_family = domain;
+ un->sun_path[0] = '\0';
+ vp->data = ksock;
+ }
+ return fd;
+ default:
+ error = -EINVAL;
+ break;
+ }
+
+fail:
+ if (ksock != NULL)
+ dynfree(ksock);
+ if (vp != NULL)
+ vfs_release_vnode(vp);
+
+ fd_close(fd);
+ return error;
+}
+
+/*
+ * Bind address to socket - POSIX bind(2) core
+ *
+ * @sockfd: File descriptor
+ * @addr: Address to bind
+ * @len: Sockaddr len
+ *
+ * Returns zero on success, otherwise a less
+ * than zero errno.
+ */
+int
+bind(int sockfd, const struct sockaddr *addr, socklen_t len)
+{
+ struct ksocket *ksock;
+ int error;
+
+ if ((error = get_ksock(sockfd, &ksock)) < 0) {
+ kprintf("error=%d\n", error);
+ return error;
+ }
+
+ /* Create the new mutex lock */
+ ksock->mtx = mutex_new("ksocket");
+ if (ksock->mtx == NULL) {
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * socket(7) syscall
+ *
+ * arg0: domain
+ * arg1: type
+ * arg2: protocol
+ */
+scret_t
+sys_socket(struct syscall_args *scargs)
+{
+ int domain = scargs->arg0;
+ int type = scargs->arg1;
+ int protocol = scargs->arg2;
+
+ return socket(domain, type, protocol);
+}
+
+/*
+ * bind(2) syscall
+ *
+ * arg0: sockfd
+ * arg1: addr
+ * arg2: len
+ */
+scret_t
+sys_bind(struct syscall_args *scargs)
+{
+ const struct sockaddr *u_addr = (void *)scargs->arg1;
+ struct sockaddr addr_copy;
+ int sockfd = scargs->arg0;
+ int len = scargs->arg2;
+ int error;
+
+ error = copyin(u_addr, &addr_copy, sizeof(addr_copy));
+ if (error < 0) {
+ return error;
+ }
+
+ return bind(sockfd, &addr_copy, len);
+}
+
+/*
+ * recv(2) syscall
+ *
+ * arg0: sockfd
+ * arg1: buf
+ * arg2: size
+ * arg3: flags
+ */
+scret_t
+sys_recv(struct syscall_args *scargs)
+{
+ char buf[NETBUF_LEN];
+ void *u_buf = (void *)scargs->arg1;
+ int sockfd = scargs->arg0;
+ size_t len = scargs->arg2;
+ int error, flags = scargs->arg3;
+
+ if (len > sizeof(buf)) {
+ return -ENOBUFS;
+ }
+
+ error = recv(sockfd, buf, len, flags);
+ if (error < 0) {
+ pr_error("sys_recv: recv() fail (fd=%d)\n", sockfd);
+ return error;
+ }
+
+ error = copyout(buf, u_buf, len);
+ return (error == 0) ? len : error;
+}
+
+/*
+ * send(2) syscall
+ *
+ * arg0: sockfd
+ * arg1: buf
+ * arg2: size
+ * arg3: flags
+ */
+scret_t
+sys_send(struct syscall_args *scargs)
+{
+ char buf[NETBUF_LEN];
+ const void *u_buf = (void *)scargs->arg1;
+ int sockfd = scargs->arg0;
+ size_t len = scargs->arg2;
+ int error, flags = scargs->arg3;
+
+ if (len > sizeof(buf)) {
+ return -ENOBUFS;
+ }
+
+ error = copyin(u_buf, buf, len);
+ if (error < 0) {
+ pr_error("sys_send: copyin() failure (fd=%d)\n", sockfd);
+ return error;
+ }
+
+ return send(sockfd, buf, len, flags);
+}
+
+static struct vops socket_vops = {
+ .read = NULL,
+ .write = NULL,
+ .reclaim = socket_reclaim,
+};
diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c
index cb7e1d2..dd3de4f 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -29,6 +29,7 @@
#include <sys/syscall.h>
#include <sys/sysctl.h>
+#include <sys/socket.h>
#include <sys/reboot.h>
#include <sys/types.h>
#include <sys/ucred.h>
@@ -60,6 +61,10 @@ scret_t(*g_sctab[])(struct syscall_args *) = {
sys_setuid, /* SYS_setuid */
sys_getuid, /* SYS_getuid */
sys_waitpid, /* SYS_waitpid */
+ sys_socket, /* SYS_socket */
+ sys_bind, /* SYS_bind */
+ sys_recv, /* SYS_recv */
+ sys_send, /* SYS_send */
};
const size_t MAX_SYSCALLS = NELEM(g_sctab);
diff --git a/sys/kern/kern_uio.c b/sys/kern/kern_uio.c
new file mode 100644
index 0000000..dd533c2
--- /dev/null
+++ b/sys/kern/kern_uio.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/limits.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/filedesc.h>
+
+/*
+ * Read data into POSIX.1‐2017 iovec
+ *
+ * @filedes: File descriptor number
+ * @iov: I/O vector to read file into
+ * @iovnt: Number of I/O vectors
+ */
+ssize_t
+readv(int filedes, const struct iovec *iov, int iovcnt)
+{
+ void *base;
+ size_t len;
+ ssize_t tmp, bytes_read = 0;
+
+ if (filedes < 0) {
+ return -EINVAL;
+ }
+
+ /*
+ * Make sure that this conforms to our max
+ * iovec limit.
+ */
+ if (iovcnt > IOVEC_MAX) {
+ return -EINVAL;
+ }
+
+ /*
+ * Go through each I/O vector and read a chunk
+ * of data into one.
+ */
+ for (int i = 0; i < iovcnt; ++i) {
+ base = iov[i].iov_base;
+ len = iov[i].iov_len;
+
+ /*
+ * If we encounter a base that is NULL,
+ * or if the length to read is an invalid
+ * value of zero. We can just assume this
+ * is some sort of weird list termination?
+ */
+ if (base == NULL || len == 0) {
+ break;
+ }
+
+ /* Read the file into this base */
+ tmp = fd_read(filedes, base, len);
+
+ /* Did anything go wrong? */
+ if (tmp < 0) {
+ return tmp;
+ }
+
+ /* No more data */
+ if (tmp == 0) {
+ break;
+ }
+
+ /* Read more bytes */
+ bytes_read += tmp;
+ }
+
+ return bytes_read;
+}
+
+/*
+ * Write data from POSIX.1‐2017 iovec
+ *
+ * @filedes: File descriptor number
+ * @iov: I/O vector to write to file
+ * @iovnt: Number of I/O vectors
+ */
+ssize_t
+writev(int filedes, const struct iovec *iov, int iovcnt)
+{
+ void *base;
+ size_t len;
+ ssize_t bytes_written = 0;
+ ssize_t tmp;
+
+ if (filedes < 0) {
+ return -EINVAL;
+ }
+
+ /*
+ * Are we within the limits? Return an
+ * error if not.
+ */
+ if (iovcnt > IOVEC_MAX) {
+ return -EINVAL;
+ }
+
+ for (int i = 0; i < iovcnt; ++i) {
+ base = iov[i].iov_base;
+ len = iov[i].iov_len;
+
+ /*
+ * These are invalid, whatever these are,
+ * terminate our walk through.
+ */
+ if (base == NULL || len == 0) {
+ break;
+ }
+
+ /* Write the data from the iovec */
+ tmp = fd_write(filedes, base, len);
+
+ /* Was there an error? */
+ if (tmp < 0) {
+ return tmp;
+ }
+
+ /* No more data to read? */
+ if (tmp == 0) {
+ break;
+ }
+
+ bytes_written += tmp;
+ }
+
+ return bytes_written;
+}
diff --git a/sys/kern/kern_vsr.c b/sys/kern/kern_vsr.c
new file mode 100644
index 0000000..c59be1e
--- /dev/null
+++ b/sys/kern/kern_vsr.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/vsr.h>
+#include <sys/proc.h>
+#include <sys/param.h>
+#include <sys/limits.h>
+#include <sys/syslog.h>
+#include <vm/dynalloc.h>
+#include <string.h>
+
+#define pr_trace(fmt, ...) kprintf("vsr: " fmt, ##__VA_ARGS__)
+#define pr_error(...) pr_trace(__VA_ARGS__)
+
+static uint32_t
+fnv1_hash(const char *s)
+{
+ uint32_t hash = 2166136261UL;
+ const uint8_t *p = (uint8_t *)s;
+
+ while (*p != '\0') {
+ hash ^= *p;
+ hash = hash * 0x01000193;
+ ++p;
+ }
+
+ return hash;
+}
+
+/*
+ * Add a VSR capsule to a domain.
+ */
+static void
+vsr_domain_add(struct vsr_domain *vsp, struct vsr_capsule *cap)
+{
+ struct vsr_table *tab;
+ struct vsr_capsule **slot;
+ uint32_t hash;
+
+ if (vsp == NULL || cap == NULL) {
+ return;
+ }
+
+ if (cap->name == NULL) {
+ pr_error("vsr_domain_add: cap->name == NULL\n");
+ return;
+ }
+
+ tab = &vsp->table;
+ hash = fnv1_hash(cap->name);
+ slot = &tab->capsules[hash % VSR_MAX_CAPSULE];
+
+ /* If this slot is free, set it */
+ if (*slot == NULL) {
+ *slot = cap;
+ return;
+ }
+
+ /* Handle collision */
+ TAILQ_INSERT_TAIL(&(*slot)->buckets, cap, link);
+}
+
+/*
+ * Handle VSR domain hashmap collisions.
+ *
+ * @slot: Slot that we have collided with
+ * @name: Name to lookup
+ *
+ * Returns the pointer to the actual capsule if the
+ * collision has been resolved, otherwise, NULL if the
+ * entry to look up was not found.
+ */
+static struct vsr_capsule *
+vsr_domain_clash(struct vsr_capsule *slot, const char *name)
+{
+ struct vsr_capsule *cap_ent;
+
+ TAILQ_FOREACH(cap_ent, &slot->buckets, link) {
+ if (cap_ent == NULL) {
+ continue;
+ }
+
+ if (strcmp(cap_ent->name, name) == 0) {
+ return cap_ent;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Lookup a capsule within a VSR domain
+ * by name.
+ *
+ * @vsp: Domain to lookup within
+ * @name: Name to use as lookup key
+ *
+ * Returns NULL if no entry was found.
+ */
+static struct vsr_capsule *
+vfs_domain_lookup(struct vsr_domain *vsp, const char *name)
+{
+ uint32_t hash;
+ struct vsr_table *tab;
+ struct vsr_capsule **slot;
+
+ if (vsp == NULL || name == NULL) {
+ return NULL;
+ }
+
+ tab = &vsp->table;
+ hash = fnv1_hash(name);
+ slot = &tab->capsules[hash % VSR_MAX_CAPSULE];
+
+ if (*slot == NULL) {
+ return NULL;
+ }
+
+ if (strcmp((*slot)->name, name) != 0) {
+ return vsr_domain_clash(*slot, name);
+ }
+
+ return *slot;
+}
+
+/*
+ * Destroy a VSR capsule
+ *
+ * @capule: Capsule to destroy
+ */
+static void
+vsr_destroy_capsule(struct vsr_capsule *capsule)
+{
+ struct vsr_capsule *bucket;
+ struct capsule_ops *ops;
+
+ if (capsule->name != NULL) {
+ dynfree(capsule->name);
+ capsule->name = NULL;
+ }
+
+ ops = &capsule->ops;
+ if (ops->reclaim != NULL) {
+ ops->reclaim(capsule, 0);
+ }
+
+ TAILQ_FOREACH(bucket, &capsule->buckets, link) {
+ if (bucket == NULL) {
+ continue;
+ }
+ vsr_destroy_capsule(bucket);
+ }
+
+ /* Release any held locks */
+ mutex_release(&capsule->lock);
+}
+
+/*
+ * Destroy a VSR table
+ *
+ * @tab: Table to destroy.
+ */
+static void
+vsr_destroy_table(struct vsr_table *tab)
+{
+ struct vsr_capsule *capsule;
+
+ if (tab == NULL) {
+ pr_error("vsr_destroy_table: tab is NULL\n");
+ return;
+ }
+
+ for (int i = 0; i < VSR_MAX_CAPSULE; ++i) {
+ if ((capsule = tab->capsules[i]) == NULL) {
+ continue;
+ }
+
+ vsr_destroy_capsule(capsule);
+ }
+}
+
+/*
+ * Allocate a new VSR capsule and add it to
+ * VSR domain.
+ *
+ * @type: Domain type (e.g., VSR_FILE)
+ * @name: Capsule name (e.g., "mod0.data")
+ * @sz: Length of capsulized data
+ */
+struct vsr_capsule *
+vsr_new_capsule(struct proc *td, vsr_domain_t type, const char *name)
+{
+ struct vsr_capsule *capsule;
+ struct vsr_domain *domain;
+
+ /* Valid args? */
+ if (type >= VSR_MAX_DOMAIN || td == NULL) {
+ return NULL;
+ }
+
+ /*
+ * The VSR domain must be registered for
+ * us to add any capsules to it.
+ */
+ if ((domain = td->vsr_tab[type]) == NULL) {
+ pr_error("VSR domain %d not registered\n", type);
+ return NULL;
+ }
+
+ /* Allocate a new capsule */
+ capsule = dynalloc(sizeof(*capsule));
+ if (capsule == NULL) {
+ return NULL;
+ }
+
+ memset(capsule, 0, sizeof(*capsule));
+ capsule->name = strdup(name);
+
+ TAILQ_INIT(&capsule->buckets);
+ vsr_domain_add(domain, capsule);
+ return capsule;
+}
+
+/*
+ * Allocate a new VSR domain and add it to
+ * a specific process.
+ *
+ * @type: VSR type (e.g., VSR_FILE)
+ */
+struct vsr_domain *
+vsr_new_domain(struct proc *td, vsr_domain_t type)
+{
+ struct vsr_domain *domain;
+
+ /* Valid args? */
+ if (type >= VSR_MAX_DOMAIN || td == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Do not overwrite the entry if it is
+ * already allocated and log this anomalous
+ * activity.
+ */
+ if (td->vsr_tab[type] != NULL) {
+ pr_error("[security]: type %d already allocated\n", type);
+ return NULL;
+ }
+
+ domain = dynalloc(sizeof(*domain));
+ if (domain == NULL) {
+ return NULL;
+ }
+
+ /* Initialize the domain */
+ memset(domain, 0, sizeof(*domain));
+ domain->type = type;
+
+ td->vsr_tab[type] = domain;
+ return domain;
+}
+
+/*
+ * Lookup a capsule by name for the current
+ * process.
+ */
+struct vsr_capsule *
+vsr_lookup_capsule(struct proc *td, vsr_domain_t type, const char *name)
+{
+ struct vsr_domain *domain;
+
+ if (td == NULL) {
+ return NULL;
+ }
+
+ /*
+ * The VSR domain must be registered for
+ * us to lookup any capsules from it.
+ */
+ if ((domain = td->vsr_tab[type]) == NULL) {
+ pr_error("VSR domain %d not registered\n", type);
+ return NULL;
+ }
+
+ return vfs_domain_lookup(domain, name);
+}
+
+/*
+ * Initialize per-process domains
+ */
+void
+vsr_init_domains(struct proc *td)
+{
+ if (vsr_new_domain(td, VSR_FILE) == NULL) {
+ pr_error("failed to initialize VSR file domain\n");
+ }
+}
+
+/*
+ * Destroy per-process domains
+ */
+void
+vsr_destroy_domains(struct proc *td)
+{
+ struct vsr_domain *domain;
+
+ if (td == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < VSR_MAX_DOMAIN; ++i) {
+ if ((domain = td->vsr_tab[i]) == NULL) {
+ continue;
+ }
+
+ vsr_destroy_table(&domain->table);
+ }
+}