diff options
Diffstat (limited to 'src/sys')
36 files changed, 1534 insertions, 63 deletions
diff --git a/src/sys/arch/amd64/cpu/cpu_conf.c b/src/sys/arch/amd64/cpu/cpu_conf.c index da2d747..8a3b4e6 100644 --- a/src/sys/arch/amd64/cpu/cpu_conf.c +++ b/src/sys/arch/amd64/cpu/cpu_conf.c @@ -44,7 +44,9 @@ extern void syscall_isr(void); extern void core_halt_isr(void); + void core_halt_handler(void); +int simd_init(void); void core_halt_handler(void) @@ -193,6 +195,7 @@ cpu_conf(struct pcore *pcore) pcore->self = pcore; wrmsr(IA32_GS_BASE, (uintptr_t)pcore); + simd_init(); init_vectors(); idt_load(); cpu_identify(mdcore); diff --git a/src/sys/arch/amd64/cpu/trap.c b/src/sys/arch/amd64/cpu/trap.c index ae3a0cc..94c6e83 100644 --- a/src/sys/arch/amd64/cpu/trap.c +++ b/src/sys/arch/amd64/cpu/trap.c @@ -34,6 +34,7 @@ #include <sys/param.h> #include <sys/cdefs.h> +#include <sys/errno.h> #include <sys/panic.h> #include <sys/cpuvar.h> #include <sys/syslog.h> @@ -148,6 +149,26 @@ trapframe_dump(struct trapframe *tf) tf->rbp, tf->rsp, tf->rip); } +/* + * Handle user faults + */ +static void +handle_ufault(void) +{ + struct proc *self = proc_self(); + + if (__unlikely(self == NULL)) { + panic("could not get self on fault\n"); + } + + syslog_toggle(true); + printf("** hardware violation **\n"); + syslog_toggle(false); + + proc_kill(self, -EFAULT); + __builtin_unreachable(); +} + void trap_syscall(struct trapframe *tf) { @@ -194,7 +215,8 @@ trap_handler(struct trapframe *tf) { trapframe_dump(tf); if (ISSET(tf->cs, 3)) { - panic("fatal user trap\n"); + handle_ufault(); + __builtin_unreachable(); } panic("fatal trap\n"); diff --git a/src/sys/arch/amd64/os/os_panic.c b/src/sys/arch/amd64/os/os_panic.c index 88e962e..996ba13 100644 --- a/src/sys/arch/amd64/os/os_panic.c +++ b/src/sys/arch/amd64/os/os_panic.c @@ -37,12 +37,16 @@ __dead void panic(const char *fmt, ...) { static va_list ap; + struct pcore *core = this_core(); + uint32_t core_id; cpu_halt_others(); va_start(ap, fmt); - printf("lunos panic: "); + core_id = (core == NULL) ? 0xFF : core->id; + printf("lunos panic[cpu %d]: ", core_id); vprintf(fmt, &ap); + for (;;) { md_intoff(); md_halt(); diff --git a/src/sys/arch/amd64/simd.S b/src/sys/arch/amd64/simd.S new file mode 100644 index 0000000..f0673f9 --- /dev/null +++ b/src/sys/arch/amd64/simd.S @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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. + */ + .text + .globl simd_init +simd_init: + /* + * Enable SIMD, if SSE and AVX is supported, + * a value of zero is returned. If SSE is + * supported yet AVX is not, a value of one + * is returned. However, if none are supported, + * this routine returns -1. + */ + + // Do we support SSE? + mov $1, %eax + cpuid + bt $25, %edx + jnc .sse_not_sup + + mov %cr0, %rax // Old CR0 -> EAX + and $0xFFFB, %ax // Disable co-processor emulation + or $0x02, %ax // Enable co-processor monitoring + mov %rax, %cr0 // Update CR0 with new flags + + mov %cr4, %rax // Old CR4 -> EAX + or $0x200, %ax // Enable FXSAVE/FXRSTOR + or $0x400, %ax // Enable SIMD FP exceptions + mov %rax, %cr4 // Update CR4 with new flags + + mov $1, %eax // LEAF 1 + cpuid // Bit 28 of ECX indicates AVX support + mov $3, %eax // We need to check two bits + shl $27, %eax // Which are ECX.OSXSAVE and ECX.AVX + test %eax, %ecx // Are XSAVE and AVX supported? + jnc .avx_not_sup // Nope, just continue + + // Enable AVX + xor %rcx, %rcx // Select XCR0 + xgetbv // Load extended control register + or $0x07, %eax // Set AVX + SSE bits + xsetbv // Store new flags + xor %rax, %rax // Everything is good + retq // Return back to caller (RETURN) +.sse_not_sup: + mov $-1, %rax + retq +.avx_not_sup: + mov $1, %rax + retq diff --git a/src/sys/fs/devfs.c b/src/sys/fs/devfs.c index 7553003..0e6b8ef 100644 --- a/src/sys/fs/devfs.c +++ b/src/sys/fs/devfs.c @@ -72,12 +72,13 @@ devfs_lookup(struct vop_lookup_args *args) } /* Found it! Create a vnode */ - error = vfs_valloc(&vp, VTYPE_FILE, 0); + error = vfs_valloc(&vp, VTYPE_CDEV, 0); if (error < 0) { return error; } vp->data = dnp; + vp->vops = &devfs_vops; *args->vpp = vp; return 0; } @@ -116,6 +117,7 @@ devfs_register(const char *name, dev_type_t type, void *devsw, int flags) break; } + dnp->dev = devsw; devname_len = strlen(name); memcpy(dnp->name, name, devname_len); TAILQ_INSERT_TAIL(&nodelist, dnp, link); @@ -123,6 +125,53 @@ devfs_register(const char *name, dev_type_t type, void *devsw, int flags) } /* + * Read a character device + */ +static int +devfs_cdev_read(struct devfs_node *dnp, struct dev_iobuf *iobuf, int flags) +{ + struct cdevsw *cdev; + + if (dnp == NULL || iobuf == NULL) { + return -EINVAL; + } + + if ((cdev = dnp->cdev) == NULL) { + return -EIO; + } + + return cdev->read(dnp, iobuf, flags); +} + +/* + * VFS read callback for devfs + */ +static ssize_t +devfs_read(struct vop_rw_data *args) +{ + struct vnode *vp; + struct devfs_node *dnp; + struct dev_iobuf iobuf; + + if ((vp = args->vp) == NULL) { + return -EIO; + } + + if ((dnp = vp->data) == NULL) { + return -EIO; + } + + iobuf.buf = args->data; + iobuf.count = args->len; + iobuf.off = args->off; + if (dnp->type == DEVFS_CDEV) { + return devfs_cdev_read(dnp, &iobuf, 0); + } + + return -EIO; +} + +/* * Initialize the device filesystem */ static int @@ -157,10 +206,11 @@ devfs_mount(struct fs_info *fip, struct mount_args *margs) } static struct vop devfs_vops = { - .lookup = devfs_lookup + .lookup = devfs_lookup, + .read = devfs_read }; -struct vfsops g_devfs_vfops = { +struct vfsops g_devfs_vfsops = { .init = devfs_init, .mount = devfs_mount }; diff --git a/src/sys/fs/tmpfs.c b/src/sys/fs/tmpfs.c new file mode 100644 index 0000000..3048fb4 --- /dev/null +++ b/src/sys/fs/tmpfs.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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/types.h> +#include <sys/mount.h> +#include <sys/syslog.h> +#include <sys/errno.h> +#include <sys/queue.h> +#include <sys/param.h> +#include <os/vnode.h> +#include <os/kalloc.h> +#include <string.h> + +#define TMPFS_NAMEMAX 128 +#define TMPFS_INIT_SIZE 8 + +/* + * Represents a single tmpfs node + */ +struct tmpfs_node { + char name[TMPFS_NAMEMAX]; + char *data; + size_t len; + size_t real_len; + int ref; + vtype_t vtype; /* vnode vtype mapping */ + TAILQ_ENTRY(tmpfs_node) link; +}; + +#define tmpfs_ref(TMP_NODEP) \ + atomic_inc_int(&(TMP_NODEP)->ref) + +static TAILQ_HEAD(, tmpfs_node) tmpfs; +static struct vop tmpfs_vops; + +/* + * Create a new tmpfs node + * + * @name: Name of node to create + * @type: Type of vnode file should be associated with + * @np_res: Result pointer is written here + * + * Returns zero on success, otherwise a less than + * zero value on failure + */ +static int +tmpfs_new(const char *name, vtype_t type, struct tmpfs_node **np_res) +{ + struct tmpfs_node *np; + size_t name_len; + + if (name == NULL) { + return -EINVAL; + } + + name_len = strlen(name); + if (name_len > sizeof(np->name) - 1) { + return -ENAMETOOLONG; + } + + np = kalloc(sizeof(*np)); + if (np == NULL) { + return -ENOMEM; + } + + memset(np, 0, sizeof(*np)); + np->data = kalloc(TMPFS_INIT_SIZE); + if (np->data == NULL) { + kfree(np); + return -ENOMEM; + } + + np->real_len = 0; + np->len = TMPFS_INIT_SIZE; + np->ref = 1; + np->vtype = type; + memset(np->data, 0, TMPFS_INIT_SIZE); + memcpy(np->name, name, name_len); + + if (np_res != NULL) { + *np_res = np; + } + + TAILQ_INSERT_TAIL(&tmpfs, np, link); + return 0; +} + +/* + * Lookup a tmpfs node by name + * + * @name: Name to lookup + * @np_res: Result is written here + */ +static int +tmpfs_byname(const char *name, struct tmpfs_node **np_res) +{ + struct tmpfs_node *npcur; + int retval = -ENOENT; + + if (name == NULL || np_res == NULL) { + return -EINVAL; + } + + TAILQ_FOREACH(npcur, &tmpfs, link) { + if (npcur == NULL) { + continue; + } + + if (strcmp(npcur->name, name) == 0) { + retval = 0; + *np_res = npcur; + break; + } + } + + return retval; +} + +/* + * VFS tmpfs lookup callback + */ +static int +tmpfs_lookup(struct vop_lookup_args *args) +{ + struct tmpfs_node *np; + struct vnode *vp; + int error; + + /* Sanity checks */ + if (args == NULL) + return -EINVAL; + if (args->name == NULL) + return -EINVAL; + if (args->vpp == NULL) + return -EINVAL; + + error = tmpfs_byname(args->name, &np); + if (error < 0) { + return error; + } + + error = vfs_valloc(&vp, np->vtype, 0); + if (error < 0) { + return error; + } + + /* Ref that node and give it */ + tmpfs_ref(np); + vp->data = np; + vp->vops = &tmpfs_vops; + *args->vpp = vp; + return 0; +} + +/* + * Create a tmpfs node + */ +static int +tmpfs_create(struct vop_create_args *args) +{ + struct nameidata *ndp; + struct tmpfs_node *np = NULL; + + if (args == NULL) { + return -EINVAL; + } + + if ((ndp = args->ndp) == NULL) { + return -EINVAL; + } + + /* Does it already exist? */ + if (tmpfs_byname(ndp->path, &np) == 0) { + return -EEXIST; + } + + /* Only accept the types we support */ + switch (args->vtype) { + case VTYPE_FILE: + case VTYPE_SOCK: + break; + default: + return -ENOTSUP; + } + + return tmpfs_new(ndp->path, args->vtype, NULL); +} + +/* + * Initialize the temporary filesystem + */ +static int +tmpfs_init(struct fs_info *fip) +{ + TAILQ_INIT(&tmpfs); + return 0; +} + +/* + * Mount the filesystem + */ +static int +tmpfs_mount(struct fs_info *fip, struct mount_args *margs) +{ + int error; + struct vnode *vp; + + if (fip == NULL || margs == NULL) { + return -1; + } + + /* Allocate a vnode for this mountpoint */ + error = vfs_valloc(&margs->vp_res, VTYPE_DIR, 0); + if (error < 0) { + return error; + } + + vp = margs->vp_res; + vp->vops = &tmpfs_vops; + return 0; +} + +/* + * Write to the filesystem + */ +static ssize_t +tmpfs_write(struct vop_rw_data *data) +{ + struct vnode *vp; + struct tmpfs_node *np; + char *dest; + void *p; + size_t node_len, len; + size_t overflow_window; + + if (data == NULL) { + return -EINVAL; + } + + if ((vp = data->vp) == NULL) { + return -EIO; + } + + /* We need the vnode for lengths */ + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* + * Check if there is going to be any overflows + * and if so, get the overflow window and expand + * the buffer by it. + */ + len = data->len; + if ((len + data->off) > np->len) { + overflow_window = (len + data->off) - np->len; + np->len += overflow_window + 1; + + p = np->data; + np->data = krealloc(np->data, np->len); + if (np->data == NULL) { + np->data = p; + return -ENOMEM; + } + } + + np->real_len += len; + node_len = np->len; + dest = np->data + data->off; + memcpy(dest, data->data, len); + return len; +} + +static ssize_t +tmpfs_read(struct vop_rw_data *data) +{ + struct vnode *vp; + struct tmpfs_node *np; + size_t len; + char *dest, *src; + + if (data == NULL) { + return -1; + } + + if ((vp = data->vp) == NULL) { + return -EIO; + } + + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* Return EOF if the offset is too far */ + len = data->len; + if (data->off >= np->real_len) { + return 0; /* EOF */ + } + + /* Is there any data to read? */ + if ((len + data->off) > np->len) { + len = np->len; + } + if (len == 0) { + return 0; + } + + dest = data->data; + src = np->data + data->off; + memcpy(dest, src, len); + return len; +} + +static int +tmpfs_getattr(struct vnode *vp, struct vattr *res) +{ + struct tmpfs_node *np; + + if (vp == NULL || res == NULL) { + return -EINVAL; + } + + if ((np = vp->data) == NULL) { + return -EIO; + } + + res->size = np->real_len; + return 0; +} + +static int +tmpfs_reclaim(struct vnode *vp, int flags) +{ + return 0; +} + +static struct vop tmpfs_vops = { + .lookup = tmpfs_lookup, + .create = tmpfs_create, + .reclaim = tmpfs_reclaim, + .write = tmpfs_write, + .read = tmpfs_read, + .getattr = tmpfs_getattr +}; + +struct vfsops g_tmpfs_vfsops = { + .init = tmpfs_init, + .mount = tmpfs_mount, +}; diff --git a/src/sys/include/compat/unix/syscall.h b/src/sys/include/compat/unix/syscall.h index a031872..5df3c51 100644 --- a/src/sys/include/compat/unix/syscall.h +++ b/src/sys/include/compat/unix/syscall.h @@ -31,12 +31,15 @@ #define _UNIX_SYSCALL_H_ 1 #include <sys/proc.h> +#include <sys/socket.h> #include <sys/param.h> #include <sys/mount.h> #include <sys/syscall.h> +#include <os/ucred.h> #include <os/iotap.h> #include <os/reboot.h> #include <dms/dms.h> +#include <vm/map.h> /* * Exit the current process - exit(2) syscall @@ -73,6 +76,11 @@ scret_t sys_read(struct syscall_args *scargs); */ scret_t sys_close(struct syscall_args *scargs); +/* + * Seek a file descriptor + */ +scret_t sys_lseek(struct syscall_args *scargs); + #ifdef _NEED_UNIX_SCTAB scret_t(*g_unix_sctab[])(struct syscall_args *) = { [SYS_none] = NULL, @@ -89,7 +97,12 @@ scret_t(*g_unix_sctab[])(struct syscall_args *) = { [SYS_waitpid] = sys_waitpid, [SYS_dmsio] = sys_dmsio, [SYS_read] = sys_read, - [SYS_close] = sys_close + [SYS_close] = sys_close, + [SYS_lseek] = sys_lseek, + [SYS_socket] = sys_socket, + [SYS_listen] = sys_listen, + [SYS_seteuid] = sys_seteuid, + [SYS_mmap] = sys_mmap }; #endif /* !_NEED_UNIX_SCTAB */ diff --git a/src/sys/include/fs/devfs.h b/src/sys/include/fs/devfs.h index ea96cdd..68c910f 100644 --- a/src/sys/include/fs/devfs.h +++ b/src/sys/include/fs/devfs.h @@ -45,6 +45,7 @@ struct devfs_node; struct dev_iobuf { void *buf; size_t count; + off_t off; }; /* diff --git a/src/sys/include/os/filedesc.h b/src/sys/include/os/filedesc.h index a6a2ac5..95400ed 100644 --- a/src/sys/include/os/filedesc.h +++ b/src/sys/include/os/filedesc.h @@ -30,6 +30,7 @@ #ifndef _OS_FILEDESC_H_ #define _OS_FILEDESC_H_ 1 +#include <sys/seek.h> #include <sys/types.h> #include <os/vnode.h> @@ -51,6 +52,18 @@ struct filedesc { }; /* + * Allocate a file descriptor from a specific process's + * file descriptor table + * + * @procp: Process to allocate fd from + * @fd_res: Result pointer is written here + * + * Returns zero on success, otherwise a less than + * zero value upon failure + */ +int fd_alloc(struct proc *procp, struct filedesc **fd_res); + +/* * Duplicate a file descriptor * * @procp: Process to duplicate from @@ -62,6 +75,18 @@ struct filedesc { struct filedesc *fd_dup(struct proc *procp, int fd); /* + * Look up a file descriptor that belongs to a specific + * process by using its fd number + * + * @procp: Process to look up + * @fd: File descriptor number + * + * Returns the file descriptor pointer on success, + * otherwise a less than zero value on failure + */ +struct filedesc *fd_get(struct proc *procp, int fd); + +/* * Initialize a process file descriptor table * and set up standard streams * @@ -117,4 +142,13 @@ ssize_t write(int fd, const void *buf, size_t count); */ ssize_t read(int fd, void *buf, size_t count); +/* + * Reposition the file offset of a file + * + * @fd: File descriptor to reposition + * @offset: Offset to move `fd' to + * @whence: How it should be repositioned + */ +off_t lseek(int fd, off_t offset, int whence); + #endif /* !_OS_FILEDESC_H_ */ diff --git a/src/sys/include/os/kalloc.h b/src/sys/include/os/kalloc.h index 143c4f9..aaaaa74 100644 --- a/src/sys/include/os/kalloc.h +++ b/src/sys/include/os/kalloc.h @@ -48,6 +48,14 @@ void *kalloc(size_t sz); /* + * Reallocates memory pool created by `dynalloc()' + * + * @old_ptr: Pointer to old pool. + * @newsize: Size of new pool. + */ +void *krealloc(void *old_ptr, size_t newsize); + +/* * Free a chunk of memory given to by * `ptr' * diff --git a/src/sys/include/os/ucred.h b/src/sys/include/os/ucred.h new file mode 100644 index 0000000..6e3e4b4 --- /dev/null +++ b/src/sys/include/os/ucred.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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 _OS_UCRED_H_ +#define _OS_UCRED_H_ 1 + +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/ucred.h> +#include <sys/proc.h> + +/* + * Initialize user credientials + * + * @proc: Current process + * @cred: credientials to initialize + * + * XXX: 'proc' being NULL drops the creds to root + * + * Returns zero on success, otherwise a less + * than zero value on failure. + */ +int ucred_init(struct proc *proc, struct ucred *cred); + +/* + * Set effective user ID + */ +int seteuid(uid_t euid); + +/* + * Set EUID system call + */ +scret_t sys_seteuid(struct syscall_args *scargs); + +#endif /* !_OS_UCRED_H_ */ diff --git a/src/sys/include/os/vnode.h b/src/sys/include/os/vnode.h index 1bef1e2..9d8a3e6 100644 --- a/src/sys/include/os/vnode.h +++ b/src/sys/include/os/vnode.h @@ -32,6 +32,7 @@ #include <sys/types.h> #include <sys/atomic.h> +#include <sys/namei.h> /* Forward declarations */ struct vnode; @@ -43,12 +44,16 @@ struct vop; * @VTYPE_NONE: Vnode is yet to be assigned a type * @VTYPE_FILE: Vnode references a file * @VTYPE_DIR: Vnode references a directory + * @VTYPE_SOCK: Vnode references a socket + * @VTYPE_CDEV: Vnode references a character device * @__N_VTYPE: Number of valid nodes on the system */ typedef enum { VTYPE_NONE, VTYPE_FILE, VTYPE_DIR, + VTYPE_SOCK, + VTYPE_CDEV, __N_VTYPE } vtype_t; @@ -83,12 +88,35 @@ struct vop_rw_data { }; /* + * Arguments to create an entry within a + * filesystem + * + * @ndp: Path component to create + * @vtype: Vnode type + */ +struct vop_create_args { + struct nameidata *ndp; + vtype_t vtype; +}; + +/* + * Represents attributes of a vnode + * + * @size: File size in bytes + */ +struct vattr { + size_t size; +}; + +/* * Represents operations that can be performed on * a specific vnode. These are implemented as callbacks */ struct vop { + int(*getattr)(struct vnode *vp, struct vattr *res); int(*lookup)(struct vop_lookup_args *args); int(*reclaim)(struct vnode *vp, int flags); + int(*create)(struct vop_create_args *args); ssize_t(*write)(struct vop_rw_data *data); ssize_t(*read)(struct vop_rw_data *data); }; @@ -176,4 +204,28 @@ ssize_t vop_read(struct vnode *vp, char *data, off_t off, size_t len); */ int vop_reclaim(struct vnode *vp, int flags); +/* + * Create a node within a specific filesystem or + * directory + * + * @vp: Vnode of parent directory + * @ndp: Namei descriptor of path component + * @type: Vnode type to create with + * + * Returns zero on success, otherwise a less than zero + * value on failure. + */ +int vop_create(struct vnode *vp, struct nameidata *ndp, vtype_t type); + +/* + * Get the attributes of a file + * + * @vp: Vnode of file to get attributes of + * @res: Result of file to get attr of + * + * Returns zero on success, otherwise a less than + * zero value on failure + */ +int vop_getattr(struct vnode *vp, struct vattr *res); + #endif /* !_OS_VNODE_H_ */ diff --git a/src/sys/include/sys/fcntl.h b/src/sys/include/sys/fcntl.h index 30d2ec4..1ab3e71 100644 --- a/src/sys/include/sys/fcntl.h +++ b/src/sys/include/sys/fcntl.h @@ -43,6 +43,7 @@ #define O_RDONLY 0x00 #define O_RDWR BIT(1) #define O_WRONLY BIT(2) +#define O_CREAT BIT(3) /* File access mode flags */ #define O_ACCMODE (O_RDWR | O_WRONLY) diff --git a/src/sys/include/sys/mman.h b/src/sys/include/sys/mman.h index 7ae1ed2..0ad4959 100644 --- a/src/sys/include/sys/mman.h +++ b/src/sys/include/sys/mman.h @@ -30,7 +30,11 @@ #ifndef _SYS_MMAN_H_ #define _SYS_MMAN_H_ 1 +#include <sys/types.h> #include <sys/param.h> +#if !defined(_KERNEL) +#include <stddef.h> +#endif /* !_KERNEL */ #define PROT_READ BIT(0) #define PROT_WRITE BIT(1) @@ -39,4 +43,9 @@ #define PROT_USER BIT(3) #endif /* _KERNEL */ +/* + * Map memory pages + */ +void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); + #endif /* !_SYS_MMAN_H_ */ diff --git a/src/sys/include/sys/mount.h b/src/sys/include/sys/mount.h index 6d041ee..5f6fa6b 100644 --- a/src/sys/include/sys/mount.h +++ b/src/sys/include/sys/mount.h @@ -42,6 +42,7 @@ */ #define MOUNT_INITRD "initrd" /* Initial ramdisk */ #define MOUNT_DEVFS "devfs" /* Device filesystem */ +#define MOUNT_TMPFS "tmpfs" /* Temporary filesystem */ /* * The mount system call @@ -65,7 +66,8 @@ struct mount; /* Filesystem vfsops */ extern struct vfsops g_omar_vfsops; -extern struct vfsops g_devfs_vfops; +extern struct vfsops g_devfs_vfsops; +extern struct vfsops g_tmpfs_vfsops; /* * Represents a mountpoint @@ -133,7 +135,6 @@ struct fs_info { */ #define FS_ATTR_IMAGE BIT(0) /* Is an image kind e.g., OSMORA OMAR */ - /* * VFS operations vector * diff --git a/src/sys/include/sys/namei.h b/src/sys/include/sys/namei.h index 58307b1..9e78a4c 100644 --- a/src/sys/include/sys/namei.h +++ b/src/sys/include/sys/namei.h @@ -32,6 +32,8 @@ #include <os/vnode.h> +#define NAMEI_CREATE BIT(0) /* Create as we go */ + /* * Represents namei data that can be used for * looking up files diff --git a/src/sys/include/sys/proc.h b/src/sys/include/sys/proc.h index a547233..b188d50 100644 --- a/src/sys/include/sys/proc.h +++ b/src/sys/include/sys/proc.h @@ -30,6 +30,7 @@ #ifndef _SYS_PROC_H_ #define _SYS_PROC_H_ +#include <sys/ucred.h> #include <sys/types.h> #include <sys/syscall.h> #include <sys/cdefs.h> @@ -91,6 +92,7 @@ struct proc { struct penv_blk *envblk; struct ptrbox *envblk_box; struct proc *parent; + struct ucred cred; mac_level_t level; struct spinlock maplist_lock; sigtab_t sigtab; diff --git a/src/sys/include/sys/seek.h b/src/sys/include/sys/seek.h new file mode 100644 index 0000000..1edc50b --- /dev/null +++ b/src/sys/include/sys/seek.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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_SEEK_H_ +#define _SYS_SEEK_H_ 1 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#endif /* !_SYS_SEEK_H_ */ diff --git a/src/sys/include/sys/socket.h b/src/sys/include/sys/socket.h new file mode 100644 index 0000000..0ca041f --- /dev/null +++ b/src/sys/include/sys/socket.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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_ 1 + +#include <sys/types.h> +#include <sys/syscall.h> + +/* Address family defines */ +#define AF_UNIX 0x00 /* Local comms / IPC */ +#define AF_LOCAL AF_UNIX /* AF_UNIX alias */ + +/* Socket type defines */ +#define SOCK_STREAM 0x00 +#define SOCK_DGRAM 0x01 + +/* + * Get a socket as a file descriptor + * + * @domain: Socket domain (AF_*) + * @type: Socket type SOCK_* + * + * Returns file descriptor on success, otherwise + * a less than zero value on failure + */ +int socket(int domain, int type, int protocol); + +/* + * @socket: Socket to listen on + * @backlog: Max connections + */ +int listen(int socket, int backlog); + +#if defined(_KERNEL) + +/* + * Kernel representation of a socket + * + * @backlog: Maximum connections (< 0 means socket not active) + */ +struct ksocket { + int backlog; +}; + +/* + * Socket syscall + */ +scret_t sys_socket(struct syscall_args *scargs); + +/* + * Listen syscall + */ +scret_t sys_listen(struct syscall_args *scargs); + +#endif /* _KERNEL */ +#endif /* !_SYS_SOCKET_H_ */ diff --git a/src/sys/include/sys/syscall.h b/src/sys/include/sys/syscall.h index 77b7505..ee6ef48 100644 --- a/src/sys/include/sys/syscall.h +++ b/src/sys/include/sys/syscall.h @@ -58,6 +58,11 @@ #define SYS_dmsio 0x0D /* DMS I/O */ #define SYS_read 0x0E /* read a file descriptor */ #define SYS_close 0x0F /* close a file */ +#define SYS_lseek 0x10 /* seek to end of file */ +#define SYS_socket 0x11 /* get a socket fd */ +#define SYS_listen 0x12 /* listen on a socket */ +#define SYS_seteuid 0x13 /* set effective UID */ +#define SYS_mmap 0x14 /* map a virtual address */ typedef __ssize_t scret_t; typedef __ssize_t scarg_t; diff --git a/src/sys/include/sys/types.h b/src/sys/include/sys/types.h index b1d5994..745eed7 100644 --- a/src/sys/include/sys/types.h +++ b/src/sys/include/sys/types.h @@ -96,7 +96,6 @@ typedef __size_t uintptr_t; typedef __size_t off_t; typedef int pid_t; typedef int dev_t; -typedef __uint32_t uid_t; typedef __uint32_t mode_t; typedef __uint32_t ino_t; typedef __uint32_t nlink_t; diff --git a/src/sys/include/sys/ucred.h b/src/sys/include/sys/ucred.h new file mode 100644 index 0000000..ab44b6c --- /dev/null +++ b/src/sys/include/sys/ucred.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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_UCRED_H_ +#define _SYS_UCRED_H_ 1 + +#include <sys/types.h> + +/* + * Represents current user credientials + * + * @euid: Effective user ID + * @ruid: Real user ID + * @suid: Saved UID + */ +struct ucred { + uid_t euid; + uid_t ruid; + uid_t suid; +}; + +#endif /* !_SYS_UCRED_H_ */ diff --git a/src/sys/include/vm/map.h b/src/sys/include/vm/map.h index 69d7d73..8183b62 100644 --- a/src/sys/include/vm/map.h +++ b/src/sys/include/vm/map.h @@ -31,6 +31,7 @@ #define _VM_MAP_H_ 1 #include <sys/types.h> +#include <sys/syscall.h> #include <sys/mman.h> #include <machine/vas.h> /* standard */ #include <vm/mmu.h> @@ -52,4 +53,9 @@ */ int vm_map(struct vm_vas *vas, struct mmu_map *spec, size_t len, int prot); +/* + * POSIX mmap syscall + */ +scret_t sys_mmap(struct syscall_args *scargs); + #endif /* !_VM_MAP_H_ */ diff --git a/src/sys/io/cons/cons.c b/src/sys/io/cons/cons.c index a80644c..65d1f1b 100644 --- a/src/sys/io/cons/cons.c +++ b/src/sys/io/cons/cons.c @@ -37,6 +37,8 @@ #include <stdbool.h> #include <string.h> +#define TAB_WIDTH (FONT_WIDTH * 4) + /* kconf background color config */ #if defined(__CONS_BG) #define DEFAULT_BG __CONS_BG @@ -180,6 +182,21 @@ cons_backspace(struct cons_scr *scr) cons_draw_cursor(scr, false); } +static void +cons_tab(struct cons_scr *scr) +{ + cons_draw_cursor(scr, true); + scr->text_x += TAB_WIDTH; + scr->cursor_x += TAB_WIDTH; + + /* Wrap to next line if needed */ + if (scr->cursor_x >= scr->max_col) { + cons_newline(scr); + } + + cons_draw_cursor(scr, false); +} + /* * Fill a screen with a desired background * color @@ -224,6 +241,9 @@ cons_handle_spec(struct cons_scr *scr, int c) case ASCII_BS: cons_backspace(scr); return c; + case ASCII_HT: + cons_tab(scr); + return c; } return -1; diff --git a/src/sys/io/ic/ahci.c b/src/sys/io/ic/ahci.c index 383e531..f4b38d2 100644 --- a/src/sys/io/ic/ahci.c +++ b/src/sys/io/ic/ahci.c @@ -665,6 +665,7 @@ ahci_init_port(struct ahci_hba *hba, struct ahci_port *port) const uint16_t BSIZE = 512; volatile struct hba_port *regs; struct ahci_cmd_hdr *cmdlist; + struct ahci_port *port_cpy; uint32_t cmd, lo, hi; size_t clen; paddr_t pa; @@ -718,8 +719,14 @@ ahci_init_port(struct ahci_hba *hba, struct ahci_port *port) return error; } - TAILQ_INSERT_TAIL(&portlist, port, link); - ahci_identify(hba, port); + port_cpy = kalloc(sizeof(*port_cpy)); + if (port_cpy == NULL) { + return -ENOMEM; + } + + memcpy(port_cpy, port, sizeof(*port_cpy)); + TAILQ_INSERT_TAIL(&portlist, port_cpy, link); + ahci_identify(hba, port_cpy); return 0; } @@ -730,7 +737,7 @@ static int ahci_init_ports(struct ahci_hba *hba) { volatile struct hba_memspace *io = hba->io; - struct ahci_port *port; + struct ahci_port port; uint32_t pi, nbits; int error; @@ -743,20 +750,13 @@ ahci_init_ports(struct ahci_hba *hba) /* Allocate a new port descriptor */ dtrace("port %d implemented\n", i); - port = kalloc(sizeof(*port)); - if (port == NULL) { - dtrace("failed to allocate port\n"); - continue; - } - - port->io = &io->ports[i]; - port->portno = i; - port->parent = hba; + port.io = &io->ports[i]; + port.portno = i; + port.parent = hba; /* Initialize the port */ - error = ahci_init_port(hba, port); + error = ahci_init_port(hba, &port); if (error < 0) { - ahci_port_detach(port); dtrace("port init failed (error=%d)\n", error); continue; } diff --git a/src/sys/os/os_filedes.c b/src/sys/os/os_filedes.c index 95452af..3eaee0d 100644 --- a/src/sys/os/os_filedes.c +++ b/src/sys/os/os_filedes.c @@ -44,16 +44,9 @@ #define STDOUT_FILENO 1 /* - * Allocate a file descriptor from a specific process's - * file descriptor table - * - * @procp: Process to allocate fd from - * @fd_res: Result pointer is written here - * - * Returns zero on success, otherwise a less than - * zero value upon failure + * Allocate a file descriptor */ -static int +int fd_alloc(struct proc *procp, struct filedesc **fd_res) { struct filedesc *fd; @@ -91,16 +84,9 @@ fd_alloc(struct proc *procp, struct filedesc **fd_res) } /* - * Look up a file descriptor that belongs to a specific - * process by using its fd number - * - * @procp: Process to look up - * @fd: File descriptor number - * - * Returns the file descriptor pointer on success, - * otherwise a less than zero value on failure + * Get a file descriptor */ -static struct filedesc * +struct filedesc * fd_get(struct proc *procp, int fd) { struct filedesc *fdp; @@ -160,8 +146,10 @@ fd_open(const char *path, mode_t mode) { struct filedesc *fd; struct nameidata nd; + struct vop_create_args creat_args; struct proc *self = proc_self(); struct vnode *vp; + uint32_t namei_flags = 0; int error; /* We need the current proc */ @@ -180,12 +168,21 @@ fd_open(const char *path, mode_t mode) } /* + * If we are creating a new file, we'll need to + * get the parent vnode so that we can use the + * create vop. + */ + if (ISSET(mode, O_CREAT)) { + namei_flags |= NAMEI_CREATE; + } + + /* * Now we try to do the lookup, we'll need * the vnode for file references to be * useful */ nd.path = path; - nd.flags = 0; + nd.flags = namei_flags; nd.vp_res = &vp; error = namei(&nd); if (error < 0) { @@ -348,6 +345,44 @@ read(int fd, void *buf, size_t count) return retval; } +off_t +lseek(int fd, off_t offset, int whence) +{ + struct filedesc *fdp; + struct proc *self = proc_self(); + struct vattr attr; + int error; + + if (fd < 0) { + return -EBADF; + } + + fdp = fd_get(self, fd); + if (fdp == NULL) { + return -EBADF; + } + + /* Could not get vnode attributes */ + error = vop_getattr(fdp->vp, &attr); + if (error < 0) { + return 0; + } + + switch (whence) { + case SEEK_SET: + fdp->off = offset; + break; + case SEEK_CUR: + fdp->off += offset; + break; + case SEEK_END: + fdp->off = attr.size; + break; + } + + return fdp->off; +} + /* * ARG0: Path * ARG1: Mode @@ -367,3 +402,18 @@ sys_open(struct syscall_args *scargs) return fd_open(pathbuf, mode); } + +/* + * ARG0: Fd + * ARG1: Offset + * ARG2: Whence + */ +scret_t +sys_lseek(struct syscall_args *scargs) +{ + int fd = SCARG(scargs, int, 0); + off_t off = SCARG(scargs, off_t, 1); + int whence = SCARG(scargs, int, 2); + + return lseek(fd, off, whence); +} diff --git a/src/sys/os/os_iotap.c b/src/sys/os/os_iotap.c index 238acfe..54d1157 100644 --- a/src/sys/os/os_iotap.c +++ b/src/sys/os/os_iotap.c @@ -130,6 +130,9 @@ iotap_mux(const char *name, struct iotap_msg *msg) ops = desc.ops; switch (msg->opcode) { case IOTAP_OPC_READ: + if (ops->read == NULL) { + return -ENOTSUP; + } return ops->read(&desc, msg->buf, msg->len); } diff --git a/src/sys/os/os_kalloc.c b/src/sys/os/os_kalloc.c index 53e2e13..a5e48e5 100644 --- a/src/sys/os/os_kalloc.c +++ b/src/sys/os/os_kalloc.c @@ -64,6 +64,17 @@ kalloc(size_t sz) return tmp; } +void * +krealloc(void *old_ptr, size_t newsize) +{ + void *tmp; + + spinlock_acquire(&lock); + tmp = tlsf_realloc(tlsf_ctx, old_ptr, newsize); + spinlock_release(&lock); + return tmp; +} + /* * Memory deallocation */ diff --git a/src/sys/os/os_null.c b/src/sys/os/os_null.c index e142c6f..ae0fcf4 100644 --- a/src/sys/os/os_null.c +++ b/src/sys/os/os_null.c @@ -41,7 +41,7 @@ static ssize_t null_read(struct devfs_node *dnp, struct dev_iobuf *io, int flags) { /* We give you a whole lot of nothing! */ - return io->count; + return 0; } /* diff --git a/src/sys/os/os_proc.c b/src/sys/os/os_proc.c index a8f49d7..ef6c04c 100644 --- a/src/sys/os/os_proc.c +++ b/src/sys/os/os_proc.c @@ -40,6 +40,7 @@ #include <os/systm.h> #include <vm/vm.h> #include <vm/physseg.h> +#include <os/ucred.h> #include <os/elfload.h> #include <os/signal.h> #include <os/kalloc.h> @@ -386,9 +387,14 @@ proc_spawn(const char *path, struct penv_blk *envbp) proc->envblk = envbp; proc->parent = proc_self(); + error = ucred_init(proc->parent, &proc->cred); + if (error < 0) { + kfree(proc); + return error; + } + md_set_ip(proc, elf.entrypoint); sched_enq(&core->scq, proc); - TAILQ_INSERT_TAIL(&procq, proc, lup_link); return proc->pid; } diff --git a/src/sys/os/os_socket.c b/src/sys/os/os_socket.c new file mode 100644 index 0000000..a37d15f --- /dev/null +++ b/src/sys/os/os_socket.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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/mount.h> +#include <sys/syslog.h> +#include <sys/errno.h> +#include <sys/proc.h> +#include <os/vnode.h> +#include <os/kalloc.h> +#include <os/filedesc.h> +#include <string.h> + +static size_t next_sockid = 1; + +/* + * Allocate a socket file descriptor + * + * @fdp_res: Result is written here + * + * XXX: Socket vnodes are never deallocated until explicitly + * closed + * + * Returns file descriptor on success, otherwise a + * less than zero value on faulure + */ +static int +get_sock_fd(struct filedesc **fdp_res) +{ + char namebuf[256]; + struct ksocket *sock; + struct mount *mp; + struct nameidata nd; + struct filedesc *fdp; + struct proc *self = proc_self(); + struct vnode *vp; + int error; + + if (fdp_res == NULL) { + return -EINVAL; + } + + if (self == NULL) { + return -EIO; + } + + error = mount_lookup("/tmp", &mp); + if (error < 0) { + printf("socket: could not get /tmp mountpoint\n"); + return error; + } + + error = fd_alloc(self, &fdp); + if (error < 0) { + printf("socket: could not allocate fd\n"); + return error; + } + + sock = kalloc(sizeof(*sock)); + if (sock == NULL) { + fd_close(fdp->fdno); + return -EINVAL; + } + + /* Format the name */ + snprintf( + namebuf, + sizeof(namebuf), + "sock.%d", + next_sockid++ + ); + + /* Allocate a persistent vnode */ + error = vfs_valloc(&vp, VTYPE_SOCK, 0); + if (error < 0) { + printf("socket: could not allocate vnode\n"); + fd_close(fdp->fdno); + kfree(sock); + return error; + } + + /* Create the backing file */ + nd.path = namebuf; + error = vop_create(mp->vp, &nd, VTYPE_SOCK); + if (error < 0) { + printf("socket: failed to create /tmp entry\n"); + fd_close(fdp->fdno); + kfree(sock); + return error; + } + + /* Mark the socket as inactive */ + memset(sock, 0, sizeof(*sock)); + sock->backlog = -1; + + fdp->vp = vp; + vp->data = sock; + printf("socket: socket created @ /tmp/%s\n", namebuf); + return fdp->fdno; +} + +/* + * Get a socket descriptor from a fd + * + * @fd: File descriptor to look up + * @sock_res: Result pointer is written here + * + * Returns zero on success, otherwise a less + * than zero value on failure + */ +static int +get_sock(int fd, struct ksocket **sock_res) +{ + struct filedesc *fdp; + struct proc *self = proc_self(); + struct vnode *vp; + + if (fd < 0) { + return -EBADF; + } + + if (sock_res == NULL) { + return -1; + } + + if (self == NULL) { + return -EINVAL; + } + + /* Get the file descriptor */ + fdp = fd_get( + self, + fd + ); + + if (fdp == NULL) { + return -EBADF; + } + + /* We need the vnode */ + if ((vp = fdp->vp) == NULL) { + return -EIO; + } + + *sock_res = vp->data; + return 0; +} + +/* + * Any backlog value > 0 marks the socket + * as accepting connections + */ +int +listen(int socket, int backlog) +{ + struct ksocket *ksock = NULL; + int error; + + if (socket < 0) { + return -EBADF; + } + + if (backlog < 0) { + backlog = 0; + } + + error = get_sock(socket, &ksock); + if (error < 0) { + printf("listen: failed to get socket descriptor\n"); + return error; + } + + /* Set the backlog */ + ksock->backlog = backlog; + return 0; +} + +/* + * Handles the AF_UNIX domain + */ +static int +af_unix(int type, int protocol) +{ + struct filedesc *desc; + + return get_sock_fd(&desc); +} + +int +socket(int domain, int type, int protocol) +{ + if (domain < 0 || type < 0) { + return -EINVAL; + } + + switch (domain) { + case AF_UNIX: + return af_unix(type, protocol); + } + + return -1; +} + +/* + * ARG0: Domain + * ARG1: Type + * ARG2: Protocol + */ +scret_t +sys_socket(struct syscall_args *scargs) +{ + int domain = SCARG(scargs, int, 0); + int type = SCARG(scargs, int, 1); + int protocol = SCARG(scargs, int, 2); + + return socket(domain, type, protocol); +} + +/* + * ARG0: Socket fd + * @backlog: Maximum connections + */ +scret_t +sys_listen(struct syscall_args *scargs) +{ + int sockfd = SCARG(scargs, int, 0); + int backlog = SCARG(scargs, int, 1); + + return listen(sockfd, backlog); +} diff --git a/src/sys/os/os_ucred.c b/src/sys/os/os_ucred.c new file mode 100644 index 0000000..bf46308 --- /dev/null +++ b/src/sys/os/os_ucred.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project 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/types.h> +#include <sys/cdefs.h> +#include <sys/errno.h> +#include <os/ucred.h> +#include <os/ucred.h> + +int +ucred_init(struct proc *proc, struct ucred *cred) +{ + struct ucred *curcred; + + if (cred == NULL) { + return -EINVAL; + } + + if (proc != NULL) { + curcred = &proc->cred; + cred->ruid = curcred->ruid; + } else { + cred->ruid = 0; + } + + cred->euid = cred->ruid; + cred->suid = cred->ruid; + return 0; +} + +int +seteuid(uid_t euid) +{ + struct proc *self = proc_self(); + struct ucred *cred; + int retval = -EPERM; + + if (__unlikely(self == NULL)) { + return -ESRCH; + } + + /* Verify against current creds */ + cred = &self->cred; + if (euid == cred->euid || euid == cred->ruid) { + cred->euid = euid; + retval = 0; + } else if (euid == cred->suid || cred->euid == 0) { + cred->euid = euid; + retval = 0; + } + + return retval; +} + +/* + * ARG0: EUID + */ +scret_t +sys_seteuid(struct syscall_args *scargs) +{ + uid_t euid = SCARG(scargs, int, 0); + + return seteuid(euid); +} diff --git a/src/sys/os/vfs_init.c b/src/sys/os/vfs_init.c index 80d8559..1b6f815 100644 --- a/src/sys/os/vfs_init.c +++ b/src/sys/os/vfs_init.c @@ -39,7 +39,8 @@ */ static struct fs_info fstab[] = { { MOUNT_INITRD, &g_omar_vfsops, 0 }, - { MOUNT_DEVFS, &g_devfs_vfops, 0 } + { MOUNT_DEVFS, &g_devfs_vfsops, 0 }, + { MOUNT_TMPFS, &g_tmpfs_vfsops, 0 } }; /* diff --git a/src/sys/os/vfs_namei.c b/src/sys/os/vfs_namei.c index 1425c30..013c0ea 100644 --- a/src/sys/os/vfs_namei.c +++ b/src/sys/os/vfs_namei.c @@ -46,10 +46,13 @@ namei(struct nameidata *ndp) struct vnode *vp; struct vop *vops; struct vop_lookup_args lookup; + struct vop_create_args create; + struct nameidata nd_create; struct fs_info *fip; char namebuf[NAME_MAX]; + size_t root_len; const char *p, *pcur; - size_t len, i = 0; + size_t i = 0; int error; if (ndp == NULL) { @@ -61,23 +64,35 @@ namei(struct nameidata *ndp) return -EINVAL; } - error = mount_lookup("/", &mp); + /* Get rid of leading slashes */ + pcur = p; + while (*pcur == '/') { + ++pcur; + } + + /* Wait until we get the '/' */ + while (*pcur != '/' && *pcur != '\0') { + ++pcur; + } + + /* Copy the root path e.g., /tmp */ + root_len = (size_t)(pcur - p); + memcpy(namebuf, p, root_len); + error = mount_lookup(namebuf, &mp); + if (error < 0) { - printf("namei: failed to get rootfs\n"); + error = mount_lookup("/", &mp); + } + if (error < 0) { + printf("namei: could not get mount %s\n", namebuf); return error; } - vp = mp->vp; fip = mp->fs; - - if ((vops = vp->vops) == NULL) { - printf("namei: failed to get vops\n"); + if ((vp = mp->vp) == NULL) { return -EIO; } - - /* We need vops->lookup() */ - if (vops->lookup == NULL) { - printf("namei: vops does not have lookup op\n"); + if ((vops = vp->vops) == NULL) { return -EIO; } @@ -99,12 +114,11 @@ namei(struct nameidata *ndp) if (error == 0) { return 0; } + + return -ENOENT; } - printf("namei: f: %s\n", ndp->path); - printf("namei: d: /\n", ndp->path); - pcur = p; while (*pcur != '\0') { /* Get out of the slashes */ while (*pcur == '/') @@ -123,7 +137,36 @@ namei(struct nameidata *ndp) } i = 0; - printf("namei: n %s\n", namebuf); + + /* Get the vops */ + vp = mp->vp; + if ((vops = vp->vops) == NULL) { + return -EIO; + } + + /* Create as we go? */ + if (ISSET(ndp->flags, NAMEI_CREATE)) { + if (vops->create == NULL) + return -EIO; + + nd_create.path = namebuf; + create.ndp = &nd_create; + create.vtype = VTYPE_FILE; + error = vops->create(&create); + if (error < 0) + return error; + } + + /* Do the lookup */ + lookup.dirvp = vp; + lookup.vpp = &vp; + lookup.name = namebuf; + error = vops->lookup(&lookup); + if (error < 0) { + return -ENOENT; + } } - return -ENOENT; + + *ndp->vp_res = vp; + return 0; } diff --git a/src/sys/os/vfs_subr.c b/src/sys/os/vfs_subr.c index 6cb7767..0e8c605 100644 --- a/src/sys/os/vfs_subr.c +++ b/src/sys/os/vfs_subr.c @@ -224,3 +224,46 @@ vop_reclaim(struct vnode *vp, int flags) return vops->reclaim(vp, flags); } + +int +vop_create(struct vnode *vp, struct nameidata *ndp, vtype_t type) +{ + struct vop *vops; + struct vop_create_args args; + + if (vp == NULL || ndp == NULL) { + return -EINVAL; + } + + if ((vops = vp->vops) == NULL) { + return -EIO; + } + + if (vops->create == NULL) { + return -EIO; + } + + args.ndp = ndp; + args.vtype = type; + return vops->create(&args); +} + +int +vop_getattr(struct vnode *vp, struct vattr *res) +{ + struct vop *vops; + + if (vp == NULL || res == NULL) { + return -EINVAL; + } + + if ((vops = vp->vops) == NULL) { + return -EIO; + } + + if (vops->getattr == NULL) { + return -EIO; + } + + return vops->getattr(vp, res); +} diff --git a/src/sys/vm/vm_map.c b/src/sys/vm/vm_map.c index 6748348..1d801af 100644 --- a/src/sys/vm/vm_map.c +++ b/src/sys/vm/vm_map.c @@ -30,12 +30,16 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/errno.h> +#include <sys/param.h> #include <sys/syslog.h> #include <vm/physseg.h> #include <vm/mmu.h> #include <vm/map.h> #include <vm/vm.h> +#define MMAP_START 0x6F3C8E0C0000 +#define MMAP_END 0x6F3C90000000 + /* * Create a virtual to physical memory * mapping @@ -133,7 +137,60 @@ vm_map(struct vm_vas *vas, struct mmu_map *spec, size_t len, int prot) } /* Place a guard page at the end */ - spec->va = spec_cpy.va + len; - __vm_map(vas, spec, DEFAULT_PAGESIZE, 0); + spec_cpy.va = spec_cpy.va + len; + __vm_map(vas, &spec_cpy, DEFAULT_PAGESIZE, 0); return 0; } + +void * +mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) +{ + struct mmu_map spec; + struct vm_vas vas; + paddr_t pa; + int error; + + /* TODO: Support address allocation */ + if (len == 0 || addr == NULL) { + return NULL; + } + + spec.va = (uintptr_t)addr; + spec.pa = 0; + error = mmu_this_vas(&vas); + if (error < 0) { + return NULL; + } + + /* Create the mapping */ + error = vm_map(&vas, &spec, len, prot); + if (error < 0) { + return NULL; + } + + return (void *)spec.va; +} + +/* + * ARG0: Address + * ARG1: Length + * ARG2: Protection flags + * ARG3: Flags + * ARG4: Fildes + * ARG5: Offset + */ +scret_t +sys_mmap(struct syscall_args *scargs) +{ + void *address = SCARG(scargs, void *, 0); + size_t length = SCARG(scargs, size_t, 1); + int prot = SCARG(scargs, int, 2); + + prot |= PROT_USER; + if (address != NULL) { + address = PTR_OFFSET(address, MMAP_START); + } + + /* XXX: Should use rest of the args */ + return (uintptr_t)mmap(address, length, prot, 0, 0, 0); +} |