diff options
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/driver_blacklist.c | 170 | ||||
-rw-r--r-- | sys/kern/driver_subr.c | 76 | ||||
-rw-r--r-- | sys/kern/exec_elf64.c | 34 | ||||
-rw-r--r-- | sys/kern/init_main.c | 29 | ||||
-rw-r--r-- | sys/kern/kern_descrip.c | 107 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 72 | ||||
-rw-r--r-- | sys/kern/kern_krq.c | 61 | ||||
-rw-r--r-- | sys/kern/kern_panic.c | 33 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 113 | ||||
-rw-r--r-- | sys/kern/kern_sched.c | 81 | ||||
-rw-r--r-- | sys/kern/kern_spawn.c | 85 | ||||
-rw-r--r-- | sys/kern/kern_stub.c | 24 | ||||
-rw-r--r-- | sys/kern/kern_synch.c | 62 | ||||
-rw-r--r-- | sys/kern/kern_syscall.c | 11 | ||||
-rw-r--r-- | sys/kern/kern_syslog.c | 137 | ||||
-rw-r--r-- | sys/kern/kern_time.c | 76 | ||||
-rw-r--r-- | sys/kern/vfs_init.c | 3 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 47 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 44 |
20 files changed, 1181 insertions, 88 deletions
diff --git a/sys/kern/driver_blacklist.c b/sys/kern/driver_blacklist.c new file mode 100644 index 0000000..982d5c9 --- /dev/null +++ b/sys/kern/driver_blacklist.c @@ -0,0 +1,170 @@ +/* + * 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/types.h> +#include <sys/errno.h> +#include <sys/queue.h> +#include <sys/driver.h> +#include <vm/dynalloc.h> +#include <string.h> + +#define BLACKLIST_SIZE 64 + +/* + * A driver blacklist entry + * + * @name: Name of driver to be blacklisted + * @buckets: To handle collisions + */ +struct blacklist_entry { + char *name; + TAILQ_ENTRY(blacklist_entry) link; + TAILQ_HEAD(, blacklist_entry) buckets; +}; + +static struct blacklist_entry blacklist[BLACKLIST_SIZE]; + +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; +} + +/* + * Returns a bucket in case of collision + */ +static struct blacklist_entry * +blacklist_collide(struct blacklist_entry *entp, const char *name) +{ + struct blacklist_entry *tmp; + + if (entp->name == NULL) { + return NULL; + } + + TAILQ_FOREACH(tmp, &entp->buckets, link) { + if (strcmp(name, tmp->name) == 0) { + return tmp; + } + } + + return NULL; +} + +/* + * Mark a driver to be ignored during startup. + * Blacklisted drivers will not be ran. + * + * @name: Name of driver (e.g., 'ahci') + */ +int +driver_blacklist(const char *name) +{ + struct blacklist_entry *ent; + struct blacklist_entry *bucket; + size_t name_len; + uint32_t hash; + + if (name == NULL) { + return -EINVAL; + } + + hash = fnv1_hash(name); + ent = &blacklist[hash % BLACKLIST_SIZE]; + if (ent->name != NULL) { + bucket = dynalloc(sizeof(*bucket)); + if (bucket == NULL) { + return -EINVAL; + } + TAILQ_INSERT_TAIL(&ent->buckets, bucket, link); + return 0; + } + + name_len = strlen(name); + ent->name = dynalloc(name_len + 1); + if (ent->name == NULL) { + return -ENOMEM; + } + memcpy(ent->name, name, name_len + 1); + return 0; +} + +/* + * Checks if a driver name is in the blacklist. + * Returns 0 if not, otherwise 1. + */ +int +driver_blacklist_check(const char *name) +{ + struct blacklist_entry *ent; + uint32_t hash; + + if (name == NULL) { + return -EINVAL; + } + + hash = fnv1_hash(name); + ent = &blacklist[hash % BLACKLIST_SIZE]; + if (ent->name == NULL) { + return 0; + } + + if (strcmp(ent->name, name) == 0) { + return 1; + } + + ent = blacklist_collide(ent, name); + if (ent != NULL) { + return 1; + } + + return 0; +} + +/* + * Initialize each entry in the driver + * blacklist + */ +void +driver_blacklist_init(void) +{ + for (size_t i = 0; i < BLACKLIST_SIZE; ++i) { + blacklist[i].name = NULL; + TAILQ_INIT(&blacklist[i].buckets); + } +} diff --git a/sys/kern/driver_subr.c b/sys/kern/driver_subr.c new file mode 100644 index 0000000..a0f9f73 --- /dev/null +++ b/sys/kern/driver_subr.c @@ -0,0 +1,76 @@ +/* + * 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/driver.h> +#include <sys/proc.h> +#include <sys/cdefs.h> +#include <sys/syslog.h> +#include <sys/panic.h> +#include <dev/timer.h> +#include <machine/sync.h> + +/* + * Initialize early drivers + * + * XXX: This should *NOT* be called directly, + * use DRIVERS_SCHED() instead. + */ +void +__driver_init_td(void) +{ + const struct driver *dp; + struct driver_var *var; + struct proc *td; + uintptr_t start, end; + + td = this_td(); + start = (uintptr_t)__driversd_init_start; + end = (uintptr_t)__driversd_init_end; + + for (dp = (void *)start; (uintptr_t)dp < end; ++dp) { + var = dp->data; + + /* + * Check the blacklist to see if this driver + * is marked to be ignored. If so, just continue + * to the next. + */ + if (driver_blacklist_check(dp->name)) { + continue; + } + + if (var->deferred) { + dp->init(); + var->deferred = 0; + } + } + + exit1(td, 0); + __builtin_unreachable(); +} diff --git a/sys/kern/exec_elf64.c b/sys/kern/exec_elf64.c index 3767b0b..9706e77 100644 --- a/sys/kern/exec_elf64.c +++ b/sys/kern/exec_elf64.c @@ -49,11 +49,43 @@ #define PHDR(HDRP, IDX) \ (void *)((uintptr_t)HDRP + (HDRP)->e_phoff + (HDRP->e_phentsize * IDX)) +#define SHDR(HDRP, IDX) \ + (void *)((uintptr_t)HDRP + (HDRP)->e_shoff + (HDRP->e_shentsize * IDX)) + struct elf_file { char *data; size_t size; }; +static int +elf_parse_shdrs(Elf64_Ehdr *eh) +{ + Elf64_Shdr *shp; + uint32_t nshdr; + + if (eh == NULL) { + return -EINVAL; + } + + nshdr = eh->e_shnum; + for (uint32_t i = 0; i < nshdr; ++i) { + shp = SHDR(eh, i); + + /* Drop null entries */ + if (shp->sh_type == SHT_NULL) { + continue; + } + + switch (shp->sh_type) { + case SHT_NOBITS: + memset((void *)shp->sh_addr, 0x0, shp->sh_size); + break; + } + } + + return 0; +} + /* * Load the file and give back an "elf_file" * structure. @@ -192,6 +224,7 @@ elf64_load(const char *pathname, struct proc *td, struct exec_prog *prog) if ((status = elf64_verify(hdr)) != 0) goto done; + memset(loadmap, 0, sizeof(loadmap)); pcbp = &td->pcb; start = -1; end = 0; @@ -242,6 +275,7 @@ elf64_load(const char *pathname, struct proc *td, struct exec_prog *prog) } } + elf_parse_shdrs(hdr); memcpy(prog->loadmap, loadmap, sizeof(loadmap)); prog->start = start; prog->end = end; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 146c4a9..6b3e09b 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -35,6 +35,7 @@ #include <sys/exec.h> #include <sys/driver.h> #include <sys/panic.h> +#include <sys/systm.h> #include <dev/acpi/uacpi.h> #include <dev/cons/cons.h> #include <dev/acpi/acpi.h> @@ -43,7 +44,14 @@ #include <vm/vm.h> #include <string.h> -static struct proc proc0; +#define _START_PATH "/usr/sbin/init" +#if defined(_INSTALL_MEDIA) +#define _START_ARG "/usr/sbin/install" +#else +#define _START_ARG NULL +#endif /* _INSTALL_MEDIA */ + +struct proc g_proc0; static void copyright(void) @@ -57,9 +65,10 @@ start_init(void) { struct proc *td = this_td(); struct execve_args execve_args; - char *argv[] = { "/usr/bin/osh", NULL }; + char *argv[] = { _START_PATH, _START_ARG, NULL }; char *envp[] = { NULL }; + kprintf("starting init...\n"); execve_args.pathname = argv[0]; execve_args.argv = argv; execve_args.envp = envp; @@ -102,14 +111,22 @@ main(void) md_intoff(); sched_init(); + memset(&g_proc0, 0, sizeof(g_proc0)); + /* Startup pid 1 */ - memset(&proc0, 0, sizeof(proc0.tf)); - spawn(&proc0, start_init, NULL, 0, NULL); + spawn(&g_proc0, start_init, NULL, 0, NULL); + md_inton(); - /* Load all drivers */ + /* Load all early drivers */ DRIVERS_INIT(); - /* Bootstrap APs and here we go! */ + /* Only log to kmsg from here */ + syslog_silence(true); + + /* + * Bootstrap APs, schedule all other drivers + * and here we go! + */ mp_bootstrap_aps(&g_bsp_ci); sched_enter(); __builtin_unreachable(); diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d122e89..0fb026f 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -149,6 +149,7 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) { char *kbuf = NULL; ssize_t n; + uint32_t seal; struct filedesc *filedes; struct sio_txn sio; scret_t retval = 0; @@ -159,8 +160,17 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) } filedes = fd_get(fd); - kbuf = dynalloc(count); + seal = filedes->flags; + + /* Check the seal */ + if (write && !ISSET(seal, O_ALLOW_WR)) { + return -EPERM; + } + if (!write && ISSET(seal, O_WRONLY)) { + return -EPERM; + } + kbuf = dynalloc(count); if (kbuf == NULL) { retval = -ENOMEM; goto done; @@ -187,6 +197,7 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) sio.buf = kbuf; sio.offset = filedes->offset; + spinlock_acquire(&filedes->lock); if (write) { /* Copy in user buffer */ if (copyin(buf, kbuf, count) < 0) { @@ -205,19 +216,52 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) goto done; } + /* End of file? */ + if (n == 0) { + retval = 0; + goto done; + } + if (copyout(kbuf, buf, count) < 0) { retval = -EFAULT; goto done; } } + + /* Increment the offset per read */ + filedes->offset += n; retval = count; done: if (kbuf != NULL) { dynfree(kbuf); } + spinlock_release(&filedes->lock); return retval; } +static int +fd_do_create(const char *path, struct nameidata *ndp) +{ + struct vop_create_args cargs; + struct vnode *dirvp = ndp->vp; + const struct vops *vops = dirvp->vops; + int error; + + if (vops->create == NULL) { + return -EINVAL; + } + + cargs.path = path; + cargs.ppath = ndp->path; + cargs.dirvp = dirvp; + cargs.vpp = &ndp->vp; + if ((error = vops->create(&cargs)) < 0) { + return error; + } + + return 0; +} + int fd_read(unsigned int fd, void *buf, size_t count) { @@ -236,18 +280,17 @@ fd_write(unsigned int fd, void *buf, size_t count) * * @pathname: Path of file to open. * @flags: Flags to use. - * - * TODO: Use of flags. */ int fd_open(const char *pathname, int flags) { int error; + const struct vops *vops; struct filedesc *filedes; struct nameidata nd; nd.path = pathname; - nd.flags = 0; + nd.flags = ISSET(flags, O_CREAT) ? NAMEI_WANTPARENT : 0; if ((error = namei(&nd)) < 0) { return error; @@ -258,6 +301,14 @@ fd_open(const char *pathname, int flags) return error; } + vops = nd.vp->vops; + if (ISSET(flags, O_CREAT) && vops->create != NULL) { + error = fd_do_create(pathname, &nd); + } + if (error < 0) { + return error; + } + filedes->vp = nd.vp; filedes->flags = flags; return filedes->fdno; @@ -285,3 +336,51 @@ fd_dup(int fd) new_desc->vp = tmp->vp; return new_desc->fdno; } + +off_t +fd_seek(int fildes, off_t offset, int whence) +{ + struct filedesc *tmp; + struct vattr attr; + struct vop_getattr_args getattr_args; + + tmp = fd_get(fildes); + if (tmp == NULL) { + return -EBADF; + } + + getattr_args.vp = tmp->vp; + getattr_args.res = &attr; + if ((vfs_vop_getattr(tmp->vp, &getattr_args)) < 0) { + return -EPIPE; + } + + switch (whence) { + case SEEK_SET: + tmp->offset = offset; + break; + case SEEK_CUR: + tmp->offset += offset; + break; + case SEEK_END: + tmp->offset = attr.size + offset; + break; + default: + return -EINVAL; + } + + return tmp->offset; +} + +/* + * Update file offset + * + * arg0: `filedes' + * arg1: `offset' + * arg2: `whence' + */ +scret_t +sys_lseek(struct syscall_args *scargs) +{ + return fd_seek(scargs->arg0, scargs->arg1, scargs->arg2); +} diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index bf6a26e..2a53b8a 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -37,6 +37,7 @@ #include <vm/map.h> #include <vm/physmem.h> #include <machine/pcb.h> +#include <machine/cdefs.h> #include <string.h> /* @@ -87,6 +88,7 @@ execve(struct proc *td, const struct execve_args *args) release_stack(td); /* Save program state */ + md_intoff(); memcpy(&td->exec, &prog, sizeof(td->exec)); /* Set new stack and map it to userspace */ @@ -99,7 +101,7 @@ execve(struct proc *td, const struct execve_args *args) stack_top = td->stack_base + (PROC_STACK_SIZE - 1); /* Setup registers, signals and stack */ - md_td_stackinit(td, (void *)(stack_top + VM_HIGHER_HALF), &prog); + stack_top = md_td_stackinit(td, (void *)(stack_top + VM_HIGHER_HALF), &prog); setregs(td, &prog, stack_top); signals_init(td); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index d6c9168..c00f39b 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -35,6 +35,7 @@ #include <vm/vm.h> #include <vm/map.h> #include <machine/pcb.h> +#include <machine/cpu.h> #define pr_trace(fmt, ...) kprintf("exit: " fmt, ##__VA_ARGS__) #define pr_error(...) pr_trace(__VA_ARGS__) @@ -49,6 +50,10 @@ unload_td(struct proc *td) size_t len; sched_detach(td); + if (ISSET(td->flags, PROC_KTD)) { + return; + } + execp = &td->exec; auxvalp = &execp->auxval; pcbp = &td->pcb; @@ -73,47 +78,69 @@ unload_td(struct proc *td) } } +void +proc_reap(struct proc *td) +{ + struct pcb *pcbp; + vaddr_t stack_va; + paddr_t stack_pa; + + pcbp = &td->pcb; + unload_td(td); + + /* + * User space stacks are identity mapped and + * kernel space stacks are not. + */ + if (ISSET(td->flags, PROC_KTD)) { + stack_va = td->stack_base; + stack_pa = td->stack_base - VM_HIGHER_HALF; + } else { + stack_va = td->stack_base; + stack_pa = td->stack_base; + vm_unmap(pcbp->addrsp, stack_va, PROC_STACK_SIZE); + } + + vm_free_frame(stack_pa, PROC_STACK_PAGES); + pmap_destroy_vas(pcbp->addrsp); +} + /* * Kill a thread and deallocate its resources. * * @td: Thread to exit */ int -exit1(struct proc *td) +exit1(struct proc *td, int flags) { - struct pcb *pcbp; struct proc *curtd, *procp; - uintptr_t stack; + struct proc *parent; + struct cpu_info *ci; pid_t target_pid, curpid; + ci = this_cpu(); target_pid = td->pid; curtd = this_td(); - pcbp = &td->pcb; curpid = curtd->pid; - stack = td->stack_base; td->flags |= PROC_EXITING; + parent = td->parent; /* If we have any children, kill them too */ if (td->nleaves > 0) { TAILQ_FOREACH(procp, &td->leafq, leaf_link) { - exit1(procp); + if (!ISSET(procp->flags, PROC_EXITING)) + exit1(procp, flags); } } - /* - * If this is on the higher half, it is kernel - * mapped and we need to convert it to a physical - * address. - */ - if (stack >= VM_HIGHER_HALF) { - stack -= VM_HIGHER_HALF; + if (target_pid != curpid) { + proc_reap(td); } - unload_td(td); - vm_unmap(pcbp->addrsp, td->stack_base, PROC_STACK_SIZE); - vm_free_frame(stack, PROC_STACK_PAGES); - pmap_destroy_vas(pcbp->addrsp); + if (td->data != NULL) { + dynfree(td->data); + } /* * Only free the process structure if we aren't @@ -124,14 +151,21 @@ exit1(struct proc *td) dynfree(td); } else { td->flags |= PROC_ZOMB; + td->flags &= ~PROC_WAITED; } /* * If we are the thread exiting, reenter the scheduler * and do not return. */ - if (target_pid == curpid) + if (target_pid == curpid) { + ci->curtd = NULL; + if (parent->pid == 0) + sched_enter(); + + parent->flags &= ~PROC_SLEEP; sched_enter(); + } return 0; } @@ -145,6 +179,6 @@ sys_exit(struct syscall_args *scargs) struct proc *td = this_td(); td->exit_status = scargs->arg0; - exit1(td); + exit1(td, 0); __builtin_unreachable(); } diff --git a/sys/kern/kern_krq.c b/sys/kern/kern_krq.c new file mode 100644 index 0000000..c12a98c --- /dev/null +++ b/sys/kern/kern_krq.c @@ -0,0 +1,61 @@ +/* + * 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/syscall.h> +#include <sys/krq.h> +#include <sys/errno.h> +#include <sys/spinlock.h> +#include <sys/driver.h> +#include <sys/syslog.h> + +static struct spinlock krq_lock = {0}; + +/* + * Load a kernel runtime quantum (KRQ) + * + * @arg0: path + * + * XXX: If the 'path' argument is NULL, all deferrable + * drivers are loaded. + * + * TODO: Handle non-null paths where a completly seperate + * module/krq can be loaded. + */ +scret_t +sys_inject(struct syscall_args *scargs) +{ + if (scargs->arg0 != 0) { + return -EINVAL; + } + + spinlock_acquire(&krq_lock); + DRIVERS_SCHED(); + spinlock_release(&krq_lock); + return 0; +} diff --git a/sys/kern/kern_panic.c b/sys/kern/kern_panic.c index 7660fff..099f620 100644 --- a/sys/kern/kern_panic.c +++ b/sys/kern/kern_panic.c @@ -31,6 +31,7 @@ #include <sys/spinlock.h> #include <sys/syslog.h> #include <sys/reboot.h> +#include <dev/cons/cons.h> #include <machine/cdefs.h> #include <machine/cpu.h> @@ -53,10 +54,35 @@ bas(bool do_trace, int reboot_type) md_backtrace(); } + kprintf(OMIT_TIMESTAMP "\n-- ALL CORES HAVE BEEN HALTED --\n"); cpu_reboot(reboot_type); __builtin_unreachable(); } +static void +panic_screen(void) +{ + struct cons_screen *scr = &g_root_scr; + + if (scr->fb_mem != NULL) { + scr->bg = 0x8B0000; + scr->fg = 0xAABBAA; + cons_reset_cursor(scr); + cons_clear_scr(scr, 0x393B39); + } +} + +static void +do_panic(const char *fmt, va_list *ap) +{ + syslog_silence(false); + kprintf(OMIT_TIMESTAMP "panic: "); + vkprintf(fmt, ap); + bas(true, REBOOT_HALT); + + __builtin_unreachable(); +} + /* * Tells the user something terribly wrong happened then * halting the system as soon as possible. @@ -75,11 +101,9 @@ panic(const char *fmt, ...) md_intoff(); cpu_halt_others(); + panic_screen(); va_start(ap, fmt); - kprintf(OMIT_TIMESTAMP "\npanic: "); - vkprintf(fmt, &ap); - bas(true, REBOOT_HALT); - + do_panic(fmt, &ap); __builtin_unreachable(); } @@ -95,7 +119,6 @@ hcf(const char *fmt, ...) { va_list ap; - if (fmt != NULL) { va_start(ap, fmt); kprintf(OMIT_TIMESTAMP); diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c new file mode 100644 index 0000000..16cd4b2 --- /dev/null +++ b/sys/kern/kern_proc.c @@ -0,0 +1,113 @@ +/* + * 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/types.h> +#include <sys/proc.h> +#include <sys/cdefs.h> +#include <sys/vnode.h> +#include <sys/syscall.h> +#include <sys/filedesc.h> +#include <sys/fcntl.h> +#include <string.h> +#include <crc32.h> + +pid_t +getpid(void) +{ + struct proc *td; + + td = this_td(); + if (td == NULL) { + return -1; + } + + return td->pid; +} + + +pid_t +getppid(void) +{ + struct proc *td; + + td = this_td(); + if (td == NULL) { + return -1; + } + if (td->parent == NULL) { + return -1; + } + + return td->parent->pid; +} + +void +proc_coredump(struct proc *td, uintptr_t fault_addr) +{ + struct coredump core; + struct sio_txn sio; + struct vnode *vp; + char pathname[128]; + int fd; + + snprintf(pathname, sizeof(pathname), "/tmp/core.%d", td->pid); + fd = fd_open(pathname, O_RDWR | O_CREAT); + + /* ... Hopefully not */ + if (__unlikely(fd < 0)) { + return; + } + + core.pid = td->pid; + core.fault_addr = fault_addr; + memcpy(&core.tf, &td->tf, sizeof(td->tf)); + + core.checksum = crc32(&core, sizeof(core) - sizeof(core.checksum)); + vp = fd_get(fd)->vp; + + sio.buf = &core; + sio.len = sizeof(core); + sio.offset = 0; + + /* Write the core file */ + vfs_vop_write(vp, &sio); + fd_close(fd); +} + +scret_t +sys_getpid(struct syscall_args *scargs) +{ + return getpid(); +} + +scret_t +sys_getppid(struct syscall_args *scargs) +{ + return getppid(); +} diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c index c22ea25..774ba71 100644 --- a/sys/kern/kern_sched.c +++ b/sys/kern/kern_sched.c @@ -34,6 +34,7 @@ #include <sys/param.h> #include <sys/syslog.h> #include <sys/atomic.h> +#include <dev/cons/cons.h> #include <machine/frame.h> #include <machine/cpu.h> #include <machine/cdefs.h> @@ -104,12 +105,29 @@ sched_dequeue_td(void) for (size_t i = 0; i < SCHED_NQUEUE; ++i) { queue = &qlist[i]; - if (!TAILQ_EMPTY(&queue->q)) { - td = TAILQ_FIRST(&queue->q); - TAILQ_REMOVE(&queue->q, td, link); - spinlock_release(&tdq_lock); - return td; + if (TAILQ_EMPTY(&queue->q)) { + continue; } + + td = TAILQ_FIRST(&queue->q); + if (td == NULL) { + continue; + } + + while (ISSET(td->flags, PROC_SLEEP)) { + td = TAILQ_NEXT(td, link); + if (td == NULL) { + break; + } + } + + if (td == NULL) { + continue; + } + + TAILQ_REMOVE(&queue->q, td, link); + spinlock_release(&tdq_lock); + return td; } /* We got nothing */ @@ -176,20 +194,40 @@ td_pri_update(struct proc *td) } } +void +sched_switch_to(struct trapframe *tf, struct proc *td) +{ + struct cpu_info *ci; + struct pcb *pcbp; + + ci = this_cpu(); + + if (tf != NULL) { + memcpy(tf, &td->tf, sizeof(*tf)); + } + + ci->curtd = td; + pcbp = &td->pcb; + pmap_switch_vas(pcbp->addrsp); +} + /* * Perform a context switch. */ void sched_switch(struct trapframe *tf) { - struct cpu_info *ci; - struct pcb *pcbp; struct proc *next_td, *td; + struct cpu_info *ci; ci = this_cpu(); td = ci->curtd; + cons_detach(); if (td != NULL) { + if (td->pid == 0) + return; + dispatch_signals(td); td_pri_update(td); sched_save_td(td, tf); @@ -200,11 +238,7 @@ sched_switch(struct trapframe *tf) return; } - memcpy(tf, &next_td->tf, sizeof(*tf)); - ci->curtd = next_td; - pcbp = &next_td->pcb; - - pmap_switch_vas(pcbp->addrsp); + sched_switch_to(tf, next_td); sched_oneshot(false); } @@ -224,12 +258,27 @@ sched_enter(void) void sched_yield(void) { - struct proc *td = this_td(); + struct proc *td; + struct cpu_info *ci = this_cpu(); - if (td != NULL) { - td->rested = true; - sched_switch(&td->tf); + if ((td = ci->curtd) == NULL) { + return; } + + td->rested = true; + + /* FIXME: Hang yielding when waited on */ + if (ISSET(td->flags, PROC_WAITED)) { + return; + } + + ci->curtd = NULL; + md_inton(); + sched_oneshot(false); + + md_hlt(); + md_intoff(); + ci->curtd = td; } void diff --git a/sys/kern/kern_spawn.c b/sys/kern/kern_spawn.c index cb898dc..a953a6e 100644 --- a/sys/kern/kern_spawn.c +++ b/sys/kern/kern_spawn.c @@ -27,6 +27,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/spawn.h> #include <sys/proc.h> #include <sys/exec.h> #include <sys/mman.h> @@ -44,10 +45,17 @@ #define pr_trace(fmt, ...) kprintf("spawn: " fmt, ##__VA_ARGS__) #define pr_error(...) pr_trace(__VA_ARGS__) +#define ARGVP_MAX (ARG_MAX / sizeof(void *)) + static volatile size_t nthreads = 0; +/* + * TODO: envp + */ struct spawn_args { char path[PATH_MAX]; + char argv_blk[ARG_MAX]; + char *argv[ARGVP_MAX]; }; static inline void @@ -66,25 +74,22 @@ spawn_thunk(void) struct proc *cur; struct execve_args execve_args; struct spawn_args *args; - char *argv[] = { NULL, NULL }; char *envp[] = { NULL }; cur = this_td(); - args = cur->spawn_data; + args = cur->data; path = args->path; + memset(pathbuf, 0, sizeof(pathbuf)); memcpy(pathbuf, path, strlen(path)); - argv[0] = (char *)pathbuf; - execve_args.pathname = argv[0]; - execve_args.argv = argv; + execve_args.pathname = pathbuf; + execve_args.argv = (char **)&args->argv[0]; execve_args.envp = envp; - path = NULL; - dynfree(args); if (execve(cur, &execve_args) != 0) { pr_error("execve failed, aborting\n"); - exit1(this_td()); + exit1(this_td(), 0); } __builtin_unreachable(); } @@ -110,6 +115,7 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new struct proc *newproc; struct mmap_lgdr *mlgdr; int error; + pid_t pid; newproc = dynalloc(sizeof(*newproc)); if (newproc == NULL) { @@ -150,17 +156,38 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new TAILQ_INSERT_TAIL(&cur->leafq, newproc, leaf_link); atomic_inc_int(&cur->nleaves); newproc->parent = cur; - newproc->spawn_data = p; + newproc->data = p; + newproc->exit_status = -1; /* Initialize the mmap ledger */ mlgdr->nbytes = 0; RBT_INIT(lgdr_entries, &mlgdr->hd); newproc->mlgdr = mlgdr; + newproc->flags |= PROC_WAITED; newproc->pid = ++nthreads; signals_init(newproc); sched_enqueue_td(newproc); - return newproc->pid; + pid = newproc->pid; + + if (ISSET(flags, SPAWN_WAIT)) { + cur->flags |= PROC_SLEEP; + + while (ISSET(cur->flags, PROC_SLEEP)) { + sched_yield(); + } + while (!ISSET(newproc->flags, PROC_ZOMB)) { + sched_yield(); + } + + if (newproc->exit_status < 0) { + pid = newproc->exit_status; + } + + proc_reap(newproc); + } + + return pid; } /* @@ -187,19 +214,26 @@ get_child(struct proc *cur, pid_t pid) /* * arg0: The file /path/to/executable - * arg1: Optional flags (`flags') + * arg1: Argv + * arg2: Envp (TODO) + * arg3: Optional flags (`flags') */ scret_t sys_spawn(struct syscall_args *scargs) { struct spawn_args *args; - const char *u_path; + char *path; + const char *u_path, **u_argv; + const char *u_p = NULL; struct proc *td; int flags, error; + size_t len, bytes_copied = 0; + size_t argv_i = 0; td = this_td(); - flags = scargs->arg1; u_path = (const char *)scargs->arg0; + u_argv = (const char **)scargs->arg1; + flags = scargs->arg3; args = dynalloc(sizeof(*args)); if (args == NULL) { @@ -212,5 +246,30 @@ sys_spawn(struct syscall_args *scargs) return error; } + memset(args->argv, 0, ARG_MAX); + for (size_t i = 0; i < ARG_MAX - 1; ++i) { + error = copyin(&u_argv[argv_i], &u_p, sizeof(u_p)); + if (error < 0) { + dynfree(args); + return error; + } + if (u_p == NULL) { + args->argv[argv_i++] = NULL; + break; + } + + path = &args->argv_blk[i]; + error = copyinstr(u_p, path, ARG_MAX - bytes_copied); + if (error < 0) { + dynfree(args); + return error; + } + + args->argv[argv_i++] = &args->argv_blk[i]; + len = strlen(path); + bytes_copied += (len + 1); + i += len; + } + return spawn(td, spawn_thunk, args, flags, NULL); } diff --git a/sys/kern/kern_stub.c b/sys/kern/kern_stub.c index 8603fd5..17c6e54 100644 --- a/sys/kern/kern_stub.c +++ b/sys/kern/kern_stub.c @@ -40,8 +40,10 @@ sigfpe_default(int signo) static struct proc *td; td = this_td(); - kprintf("Floating point exception (pid=%d)\n", td->pid); - exit1(td); + syslog_silence(false); + kprintf(OMIT_TIMESTAMP "Floating point exception (pid=%d)\n", td->pid); + syslog_silence(true); + exit1(td, 0); } void @@ -50,8 +52,10 @@ sigkill_default(int signo) static struct proc *td; td = this_td(); - kprintf("Terminated (pid=%d)\n", td->pid); - exit1(td); + syslog_silence(false); + kprintf(OMIT_TIMESTAMP "Terminated (pid=%d)\n", td->pid); + syslog_silence(true); + exit1(td, 0); } void @@ -60,8 +64,10 @@ sigsegv_default(int signo) static struct proc *td; td = this_td(); - kprintf("Segmentation fault (pid=%d)\n", td->pid); - exit1(td); + syslog_silence(false); + kprintf(OMIT_TIMESTAMP "Segmentation fault (pid=%d)\n", td->pid); + syslog_silence(true); + exit1(td, 0); } int @@ -75,3 +81,9 @@ dev_nowrite(void) { return -ENOTSUP; } + +int +dev_nobsize(void) +{ + return -ENOTSUP; +} diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 57b27d0..497aff7 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -28,12 +28,16 @@ */ #include <sys/types.h> +#include <sys/mutex.h> #include <sys/systm.h> #include <sys/errno.h> +#include <sys/sched.h> #include <sys/atomic.h> #include <sys/syslog.h> #include <sys/spinlock.h> +#include <machine/cdefs.h> #include <dev/timer.h> +#include <string.h> #define pr_trace(fmt, ...) kprintf("synch: " fmt, ##__VA_ARGS__) #define pr_error(...) pr_trace(__VA_ARGS__) @@ -80,7 +84,9 @@ spinlock_usleep(struct spinlock *lock, size_t usec_max) void spinlock_acquire(struct spinlock *lock) { - while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)); + while (__atomic_test_and_set(&lock->lock, __ATOMIC_ACQUIRE)) { + md_pause(); + } } /* @@ -136,3 +142,57 @@ sysrel(void) { spinlock_release(&__syslock); } + +/* + * Create a new mutex lock object + */ +struct mutex * +mutex_new(const char *name) +{ + struct mutex *mtx; + size_t namelen; + + mtx = dynalloc(sizeof(*mtx)); + if (mtx == NULL) { + return NULL; + } + + mtx->lock = 0; + namelen = strlen(name); + + /* Don't overflow the name buffer */ + if (namelen >= MUTEX_NAME_LEN) { + namelen = MUTEX_NAME_LEN - 1; + } + + memcpy(mtx->name, name, namelen); + return mtx; +} + +/* + * Acquire a mutex + * + * @mtx: Mutex to acquire + * @flags: Optional flags + */ +int +mutex_acquire(struct mutex *mtx, int flags) +{ + while (__atomic_test_and_set(&mtx->lock, __ATOMIC_ACQUIRE)) { + sched_yield(); + } + + return 0; +} + +void +mutex_release(struct mutex *mtx) +{ + __atomic_clear(&mtx->lock, __ATOMIC_RELEASE); +} + +void +mutex_free(struct mutex *mtx) +{ + dynfree(mtx); +} diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c index 249a04a..739dd7f 100644 --- a/sys/kern/kern_syscall.c +++ b/sys/kern/kern_syscall.c @@ -31,8 +31,11 @@ #include <sys/sysctl.h> #include <sys/reboot.h> #include <sys/types.h> +#include <sys/time.h> +#include <sys/mman.h> #include <sys/proc.h> #include <sys/vfs.h> +#include <sys/krq.h> scret_t(*g_sctab[])(struct syscall_args *) = { NULL, /* SYS_none */ @@ -45,6 +48,14 @@ scret_t(*g_sctab[])(struct syscall_args *) = { sys_write, /* SYS_write */ sys_spawn, /* SYS_spawn */ sys_reboot, /* SYS_reboot */ + sys_mmap, /* SYS_mmap */ + sys_munmap, /* SYS_munap */ + sys_access, /* SYS_access */ + sys_lseek, /* SYS_lseek */ + sys_sleep, /* SYS_sleep */ + sys_inject, /* SYS_inject */ + sys_getpid, /* SYS_getpid */ + sys_getppid /* SYS_getppid */ }; const size_t MAX_SYSCALLS = NELEM(g_sctab); diff --git a/sys/kern/kern_syslog.c b/sys/kern/kern_syslog.c index 665734d..c7f51f7 100644 --- a/sys/kern/kern_syslog.c +++ b/sys/kern/kern_syslog.c @@ -28,9 +28,14 @@ */ #include <sys/syslog.h> +#include <sys/cdefs.h> +#include <sys/sio.h> #include <sys/spinlock.h> +#include <sys/device.h> +#include <sys/errno.h> #include <dev/cons/cons.h> #include <dev/timer.h> +#include <fs/devfs.h> #include <stdarg.h> #include <string.h> @@ -40,21 +45,105 @@ #define SERIAL_DEBUG 0 #endif +#if defined(__USER_KMSG) +#define USER_KMSG __USER_KMSG +#else +#define USER_KMSG 0 +#endif + +#define KBUF_SIZE (1 << 16) + +/* Sanity check */ +__static_assert(KBUF_SIZE <= (1 << 16), "KBUF_SIZE too high!"); + /* Global logger lock */ -static struct spinlock lock = {0}; +static struct spinlock kmsg_lock = {0}; +static bool no_cons_log = false; + +/* Kernel message buffer */ +static char kmsg[KBUF_SIZE]; +static size_t kmsg_i = 0; +static struct cdevsw kmsg_cdevw; + +static void +kmsg_append(const char *s, size_t len) +{ + spinlock_acquire(&kmsg_lock); + if ((kmsg_i + len) >= KBUF_SIZE) { + kmsg_i = 0; + } + + for (size_t i = 0; i < len; ++i) { + kmsg[kmsg_i + i] = s[i]; + } + kmsg_i += len; + spinlock_release(&kmsg_lock); +} + +/* + * Character device function. + */ +static int +kmsg_read(dev_t dev, struct sio_txn *sio, int flags) +{ + size_t len, offset, j; + size_t bytes_read = 0; + char *p = sio->buf; + + spinlock_acquire(&kmsg_lock); + len = sio->len; + offset = sio->offset; + + if (len == 0) { + spinlock_release(&kmsg_lock); + return -EINVAL; + } + if (offset >= kmsg_i) { + spinlock_release(&kmsg_lock); + return 0; + } + + for (size_t i = 0; i < len; ++i) { + j = offset + i; + if (j > kmsg_i) { + break; + } + + p[i] = kmsg[j]; + ++bytes_read; + } + + spinlock_release(&kmsg_lock); + return bytes_read; +} static void syslog_write(const char *s, size_t len) { - const char *p = s; + const char *p; + size_t l; - while (len--) { - cons_putch(&g_root_scr, *p); - if (SERIAL_DEBUG) { + if (SERIAL_DEBUG) { + p = s; + l = len; + while (l--) { serial_putc(*p); + ++p; } - ++p; } + + kmsg_append(s, len); + + /* + * If the USER_KMSG option is disabled in kconf, + * do not log to the console if everything else + * has already started. + */ + if (!USER_KMSG && no_cons_log) { + return; + } + + cons_putstr(&g_root_scr, s, len); } /* @@ -101,7 +190,6 @@ kprintf(const char *fmt, ...) } } - spinlock_acquire(&lock); if (use_timestamp) { syslog_write(timestamp, strlen(timestamp)); } @@ -110,5 +198,38 @@ kprintf(const char *fmt, ...) vkprintf(fmt_p, &ap); va_end(ap); - spinlock_release(&lock); } + +/* + * Silence kernel messages in if the system + * is already operating in a user context. + * + * XXX: This is ignored if the kconf USER_KMSG + * option is set to "no". A kmsg device file + * is also created on the first call. + */ +void +syslog_silence(bool option) +{ + static bool once = false; + static char devname[] = "kmsg"; + devmajor_t major; + dev_t dev; + + if (!once) { + once = true; + major = dev_alloc_major(); + dev = dev_alloc(major); + + dev_register(major, dev, &kmsg_cdevw); + devfs_create_entry(devname, major, dev, 0444); + + } + + no_cons_log = option; +} + +static struct cdevsw kmsg_cdevw = { + .read = kmsg_read, + .write = nowrite +}; diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c new file mode 100644 index 0000000..102648c --- /dev/null +++ b/sys/kern/kern_time.c @@ -0,0 +1,76 @@ +/* + * 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/types.h> +#include <sys/time.h> +#include <sys/syscall.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/cdefs.h> +#include <dev/timer.h> +#include <machine/cdefs.h> + +/* + * arg0: Timespec + * arg1: Remaining timeval + */ +scret_t +sys_sleep(struct syscall_args *scargs) +{ + struct timespec ts; + struct timer tmr; + size_t timeout_msec; + tmrr_status_t status; + int error; + + error = copyin((void *)scargs->arg0, &ts, sizeof(ts)); + if (error < 0) { + return error; + } + + if (ts.tv_nsec >= 1000000000) { + return -EINVAL; + } + + status = req_timer(TIMER_GP, &tmr); + if (__unlikely(status != TMRR_SUCCESS)) { + return -ENOTSUP; + } + if (__unlikely(tmr.msleep == NULL)) { + return -ENOTSUP; + } + + timeout_msec = ts.tv_nsec / 1000000; + timeout_msec += ts.tv_sec * 1000; + + md_inton(); + tmr.msleep(timeout_msec); + md_intoff(); + return 0; +} diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index 8c1bc74..bc7f8b0 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -37,7 +37,8 @@ struct vnode *g_root_vnode = NULL; static struct fs_info fs_list[] = { {MOUNT_RAMFS, &g_initramfs_vfsops, 0, 0}, {MOUNT_DEVFS, &g_devfs_vfsops, 0, 0}, - {MOUNT_CTLFS, &g_ctlfs_vfsops, 0, 0} + {MOUNT_CTLFS, &g_ctlfs_vfsops, 0, 0}, + {MOUNT_TMPFS, &g_tmpfs_vfsops, 0, 0} }; void diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index d04b812..d88c447 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -29,6 +29,7 @@ #include <sys/namei.h> #include <sys/vnode.h> +#include <sys/param.h> #include <sys/mount.h> #include <sys/errno.h> #include <vm/dynalloc.h> @@ -118,20 +119,60 @@ vfs_get_fname_at(const char *path, size_t idx) } /* + * Count the number of components that exist within + * a path minus the delimiter as well as any redundant + * delimiters. + * + * @path: Path to count + */ +static uint8_t +namei_num_cnp(const char *path) +{ + const char *p = path; + uint8_t count = 0; + + while (*p != '\0') { + /* Skip redundant delimiters */ + if (p[0] == '/' && p[1] == '/') { + ++p; + continue; + } + + if (*p == '/') { + ++count; + } + ++p; + } + + /* Don't count leading slash */ + if (*(p - 1) == '/') { + --count; + } + + return count; +} + +/* * Search for a path within a mountpoint. * * @mp: Mountpoint to search in. * @path: Path to search for. + * @ndp: Namei data pointer */ static struct vnode * -namei_mp_search(struct mount *mp, const char *path) +namei_mp_search(struct mount *mp, const char *path, struct nameidata *ndp) { struct vop_lookup_args lookup_args; struct vnode *vp = mp->vp; + uint8_t n_cnp = 0; char *name; int status; - for (size_t i = 1;; ++i) { + n_cnp = namei_num_cnp(path); + if (ISSET(ndp->flags, NAMEI_WANTPARENT)) { + --n_cnp; + } + for (size_t i = 1; i < n_cnp; ++i) { name = vfs_get_fname_at(path, i); if (name == NULL) break; @@ -212,7 +253,7 @@ namei(struct nameidata *ndp) /* If the name matches, search within */ if (strcmp(mp->name, name) == 0) - vp = namei_mp_search(mp, path); + vp = namei_mp_search(mp, path, ndp); /* Did we find it at this mountpoint? */ if (vp != NULL) { diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 990d722..0d51331 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -43,7 +43,7 @@ static int vfs_dostat(const char *path, struct stat *sbuf) { char pathbuf[PATH_MAX]; - struct vattr *attr; + struct vattr attr; struct stat st; struct vnode *vp; struct vop_getattr_args gattr; @@ -58,7 +58,7 @@ vfs_dostat(const char *path, struct stat *sbuf) return -EFAULT; } - nd.path = path; + nd.path = pathbuf; nd.flags = 0; if ((error = namei(&nd)) != 0) { @@ -67,19 +67,42 @@ vfs_dostat(const char *path, struct stat *sbuf) vp = nd.vp; gattr.vp = vp; + gattr.res = &attr; error = vfs_vop_getattr(vp, &gattr); if (error != 0) { return error; } - attr = gattr.res; memset(&st, VNOVAL, sizeof(st)); /* Copy stat data to userspace statbuf */ - st.st_mode = attr->mode; - st.st_size = attr->size; + st.st_mode = attr.mode; + st.st_size = attr.size; copyout(&st, sbuf, sizeof(*sbuf)); + vfs_release_vnode(vp); + return 0; +} + +static int +vfs_doaccess(const char *path) +{ + struct nameidata nd; + char pathbuf[PATH_MAX]; + int error; + + if ((copyinstr(path, pathbuf, sizeof(pathbuf))) < 0) { + return -EFAULT; + } + + nd.path = pathbuf; + nd.flags = 0; + + if ((error = namei(&nd)) != 0) { + return error; + } + + vfs_release_vnode(nd.vp); return 0; } @@ -149,3 +172,14 @@ sys_stat(struct syscall_args *scargs) { return vfs_dostat((const char *)scargs->arg0, (void *)scargs->arg1); } + +/* + * Check if a file can be accessed. + * + * @arg0: path + */ +scret_t +sys_access(struct syscall_args *scargs) +{ + return vfs_doaccess((const char *)scargs->arg0); +} |