summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/driver_subr.c64
-rw-r--r--sys/kern/exec_elf64.c34
-rw-r--r--sys/kern/init_main.c32
-rw-r--r--sys/kern/kern_descrip.c107
-rw-r--r--sys/kern/kern_exec.c4
-rw-r--r--sys/kern/kern_exit.c97
-rw-r--r--sys/kern/kern_panic.c8
-rw-r--r--sys/kern/kern_sched.c127
-rw-r--r--sys/kern/kern_spawn.c275
-rw-r--r--sys/kern/kern_stub.c24
-rw-r--r--sys/kern/kern_syscall.c10
-rw-r--r--sys/kern/kern_syslog.c136
-rw-r--r--sys/kern/kern_time.c (renamed from sys/kern/kern_fork.c)81
-rw-r--r--sys/kern/vfs_init.c4
-rw-r--r--sys/kern/vfs_lookup.c54
-rw-r--r--sys/kern/vfs_syscalls.c46
16 files changed, 951 insertions, 152 deletions
diff --git a/sys/kern/driver_subr.c b/sys/kern/driver_subr.c
new file mode 100644
index 0000000..29eac71
--- /dev/null
+++ b/sys/kern/driver_subr.c
@@ -0,0 +1,64 @@
+/*
+ * 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;
+ 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 667bb97..797319f 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -35,6 +35,8 @@
#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>
#include <machine/cpu.h>
@@ -42,7 +44,13 @@
#include <vm/vm.h>
#include <string.h>
-static struct proc proc0;
+#if defined(_INSTALL_MEDIA)
+#define _START_PATH "/usr/sbin/install"
+#else
+#define _START_PATH "/usr/sbin/init"
+#endif /* _INSTALL_MEDIA */
+
+struct proc g_proc0;
static void
copyright(void)
@@ -56,9 +64,10 @@ start_init(void)
{
struct proc *td = this_td();
struct execve_args execve_args;
- char *argv[] = { "/usr/bin/osh", NULL };
+ char *argv[] = { _START_PATH, NULL, NULL };
char *envp[] = { NULL };
+ kprintf("starting init...\n");
execve_args.pathname = argv[0];
execve_args.argv = argv;
execve_args.envp = envp;
@@ -95,19 +104,30 @@ main(void)
/* Expose the console to devfs */
cons_expose();
+ uacpi_init();
+
/* Start scheduler and bootstrap APs */
md_intoff();
sched_init();
+ memset(&g_proc0, 0, sizeof(g_proc0));
+
/* Startup pid 1 */
- memset(&proc0, 0, sizeof(proc0.tf));
- fork1(&proc0, 0, start_init, 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);
+ DRIVERS_SCHED();
sched_enter();
__builtin_unreachable();
}
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index d122e89..d4c9885 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 0;
+}
+
+/*
+ * 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 75ab0e9..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__)
@@ -48,6 +49,11 @@ unload_td(struct proc *td)
struct pcb *pcbp;
size_t len;
+ sched_detach(td);
+ if (ISSET(td->flags, PROC_KTD)) {
+ return;
+ }
+
execp = &td->exec;
auxvalp = &execp->auxval;
pcbp = &td->pcb;
@@ -72,56 +78,107 @@ 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;
- uintptr_t stack;
+ struct proc *curtd, *procp;
+ 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 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 we have any children, kill them too */
+ if (td->nleaves > 0) {
+ TAILQ_FOREACH(procp, &td->leafq, leaf_link) {
+ if (!ISSET(procp->flags, PROC_EXITING))
+ exit1(procp, flags);
+ }
}
- unload_td(td);
- vm_unmap(pcbp->addrsp, td->stack_base, PROC_STACK_SIZE);
- vm_free_frame(stack, PROC_STACK_PAGES);
+ if (target_pid != curpid) {
+ proc_reap(td);
+ }
- pmap_destroy_vas(pcbp->addrsp);
- dynfree(td);
+ if (td->data != NULL) {
+ dynfree(td->data);
+ }
+
+ /*
+ * Only free the process structure if we aren't
+ * being waited on, otherwise let it be so the
+ * parent can examine what's left of it.
+ */
+ if (!ISSET(td->flags, PROC_WAITED)) {
+ 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;
}
+/*
+ * arg0: Exit status.
+ */
scret_t
sys_exit(struct syscall_args *scargs)
{
- exit1(this_td());
+ struct proc *td = this_td();
+
+ td->exit_status = scargs->arg0;
+ exit1(td, 0);
__builtin_unreachable();
}
diff --git a/sys/kern/kern_panic.c b/sys/kern/kern_panic.c
index 950ea8f..7660fff 100644
--- a/sys/kern/kern_panic.c
+++ b/sys/kern/kern_panic.c
@@ -31,6 +31,8 @@
#include <sys/spinlock.h>
#include <sys/syslog.h>
#include <sys/reboot.h>
+#include <machine/cdefs.h>
+#include <machine/cpu.h>
/*
* Burn and sizzle - the core logic that really ends
@@ -69,8 +71,12 @@ panic(const char *fmt, ...)
{
va_list ap;
+ /* Shut everything else up */
+ md_intoff();
+ cpu_halt_others();
+
va_start(ap, fmt);
- kprintf(OMIT_TIMESTAMP "panic: ");
+ kprintf(OMIT_TIMESTAMP "\npanic: ");
vkprintf(fmt, &ap);
bas(true, REBOOT_HALT);
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
index 4bbe5a0..ec5592e 100644
--- a/sys/kern/kern_sched.c
+++ b/sys/kern/kern_sched.c
@@ -104,12 +104,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,62 +193,50 @@ 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;
- bool use_current = true;
+ struct cpu_info *ci;
ci = this_cpu();
td = ci->curtd;
if (td != NULL) {
- dispatch_signals(td);
- td_pri_update(td);
- }
-
- /*
- * Get the next thread and use it only if it isn't
- * in the middle of an exit, exec, or whatever.
- */
- do {
- if ((next_td = sched_dequeue_td()) == NULL) {
- sched_oneshot(false);
+ if (td->pid == 0)
return;
- }
- /*
- * If we are in the middle of an exec, don't use this
- * thread.
- */
- if (ISSET(next_td->flags, PROC_EXEC)) {
- use_current = false;
- }
-
- /*
- * Don't use this thread if we are currently
- * exiting.
- */
- if (ISSET(next_td->flags, PROC_EXITING)) {
- use_current = false;
- }
- } while (!use_current);
-
- /* Save the previous thread */
- if (td != NULL) {
+ dispatch_signals(td);
+ td_pri_update(td);
sched_save_td(td, tf);
}
- memcpy(tf, &next_td->tf, sizeof(*tf));
- ci->curtd = next_td;
- pcbp = &next_td->pcb;
+ if ((next_td = sched_dequeue_td()) == NULL) {
+ sched_oneshot(false);
+ return;
+ }
- pmap_switch_vas(pcbp->addrsp);
+ sched_switch_to(tf, next_td);
sched_oneshot(false);
}
@@ -242,9 +247,8 @@ void
sched_enter(void)
{
md_inton();
- md_sync_all();
+ sched_oneshot(false);
for (;;) {
- sched_oneshot(false);
md_pause();
}
}
@@ -252,14 +256,39 @@ 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;
+ 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);
- while (td->rested);
+
+ md_hlt();
+ md_intoff();
+ ci->curtd = td;
+}
+
+void
+sched_detach(struct proc *td)
+{
+ struct sched_queue *queue;
+
+ spinlock_acquire(&tdq_lock);
+ queue = &qlist[td->priority];
+
+ TAILQ_REMOVE(&queue->q, td, link);
+ spinlock_release(&tdq_lock);
}
void
diff --git a/sys/kern/kern_spawn.c b/sys/kern/kern_spawn.c
new file mode 100644
index 0000000..a953a6e
--- /dev/null
+++ b/sys/kern/kern_spawn.c
@@ -0,0 +1,275 @@
+/*
+ * 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/spawn.h>
+#include <sys/proc.h>
+#include <sys/exec.h>
+#include <sys/mman.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/syscall.h>
+#include <sys/atomic.h>
+#include <sys/signal.h>
+#include <sys/limits.h>
+#include <sys/sched.h>
+#include <vm/dynalloc.h>
+#include <string.h>
+
+#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
+try_free_data(void *p)
+{
+ if (p != NULL) {
+ dynfree(p);
+ }
+}
+
+static void
+spawn_thunk(void)
+{
+ const char *path;
+ char pathbuf[PATH_MAX];
+ struct proc *cur;
+ struct execve_args execve_args;
+ struct spawn_args *args;
+ char *envp[] = { NULL };
+
+ cur = this_td();
+ args = cur->data;
+ path = args->path;
+ memset(pathbuf, 0, sizeof(pathbuf));
+ memcpy(pathbuf, path, strlen(path));
+
+ execve_args.pathname = pathbuf;
+ execve_args.argv = (char **)&args->argv[0];
+ execve_args.envp = envp;
+ path = NULL;
+
+ if (execve(cur, &execve_args) != 0) {
+ pr_error("execve failed, aborting\n");
+ exit1(this_td(), 0);
+ }
+ __builtin_unreachable();
+}
+
+/*
+ * Spawn a new process
+ *
+ * @cur: Parent (current) process.
+ * @func: Address of start code.
+ * @p: Data to pass to new process (used for user procs)
+ * @flags: Spawn flags.
+ * @newprocp: If not NULL, will contain the new process.
+ *
+ * Returns the PID of the child on success, otherwise an
+ * errno value that is less than zero.
+ *
+ * XXX: `p` is only used by sys_spawn and should be set
+ * to NULL if called in the kernel.
+ */
+pid_t
+spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **newprocp)
+{
+ struct proc *newproc;
+ struct mmap_lgdr *mlgdr;
+ int error;
+ pid_t pid;
+
+ newproc = dynalloc(sizeof(*newproc));
+ if (newproc == NULL) {
+ pr_error("could not alloc proc (-ENOMEM)\n");
+ try_free_data(p);
+ return -ENOMEM;
+ }
+
+ mlgdr = dynalloc(sizeof(*mlgdr));
+ if (mlgdr == NULL) {
+ dynfree(newproc);
+ try_free_data(p);
+ pr_error("could not alloc proc mlgdr (-ENOMEM)\n");
+ return -ENOMEM;
+ }
+
+ memset(newproc, 0, sizeof(*newproc));
+ error = md_spawn(newproc, cur, (uintptr_t)func);
+ if (error < 0) {
+ dynfree(newproc);
+ dynfree(mlgdr);
+ try_free_data(p);
+ pr_error("error initializing proc\n");
+ return error;
+ }
+
+ /* Set proc output if we can */
+ if (newprocp != NULL) {
+ *newprocp = newproc;
+ }
+
+ if (!ISSET(cur->flags, PROC_LEAFQ)) {
+ TAILQ_INIT(&cur->leafq);
+ cur->flags |= PROC_LEAFQ;
+ }
+
+ /* Add to parent leafq */
+ TAILQ_INSERT_TAIL(&cur->leafq, newproc, leaf_link);
+ atomic_inc_int(&cur->nleaves);
+ newproc->parent = cur;
+ 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);
+ 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;
+}
+
+/*
+ * Get the child of a process by PID.
+ *
+ * @cur: Parent process.
+ * @pid: Child PID.
+ *
+ * Returns NULL if no child was found.
+ */
+struct proc *
+get_child(struct proc *cur, pid_t pid)
+{
+ struct proc *procp;
+
+ TAILQ_FOREACH(procp, &cur->leafq, leaf_link) {
+ if (procp->pid == pid) {
+ return procp;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * arg0: The file /path/to/executable
+ * arg1: Argv
+ * arg2: Envp (TODO)
+ * arg3: Optional flags (`flags')
+ */
+scret_t
+sys_spawn(struct syscall_args *scargs)
+{
+ struct spawn_args *args;
+ 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();
+ u_path = (const char *)scargs->arg0;
+ u_argv = (const char **)scargs->arg1;
+ flags = scargs->arg3;
+
+ args = dynalloc(sizeof(*args));
+ if (args == NULL) {
+ return -ENOMEM;
+ }
+
+ error = copyinstr(u_path, args->path, sizeof(args->path));
+ if (error < 0) {
+ dynfree(args);
+ 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_syscall.c b/sys/kern/kern_syscall.c
index 986d82a..b1deb7a 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -29,7 +29,10 @@
#include <sys/syscall.h>
#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>
@@ -42,6 +45,13 @@ scret_t(*g_sctab[])(struct syscall_args *) = {
sys_stat, /* SYS_stat */
sys_sysctl, /* SYS_sysctl */
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 */
};
const size_t MAX_SYSCALLS = NELEM(g_sctab);
diff --git a/sys/kern/kern_syslog.c b/sys/kern/kern_syslog.c
index 10bf348..eb4fa8d 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,106 @@
#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,14 +191,48 @@ kprintf(const char *fmt, ...)
}
}
+ spinlock_acquire(&lock);
if (use_timestamp) {
syslog_write(timestamp, strlen(timestamp));
}
- spinlock_acquire(&lock);
va_start(ap, 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_fork.c b/sys/kern/kern_time.c
index abb7707..102648c 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_time.c
@@ -27,61 +27,50 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/mman.h>
-#include <sys/tree.h>
#include <sys/types.h>
-#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+#include <sys/systm.h>
#include <sys/errno.h>
-#include <sys/sched.h>
-#include <sys/signal.h>
-#include <vm/dynalloc.h>
-#include <string.h>
-
-static size_t nthreads = 0;
+#include <sys/cdefs.h>
+#include <dev/timer.h>
+#include <machine/cdefs.h>
/*
- * Fork1 - fork and direct a thread to 'ip'
- *
- * @cur: Current process.
- * @flags: Flags to set.
- * @ip: Location for new thread to start at.
- * @newprocp: Will contain new thread if not NULL.
+ * arg0: Timespec
+ * arg1: Remaining timeval
*/
-int
-fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp)
+scret_t
+sys_sleep(struct syscall_args *scargs)
{
- struct proc *newproc;
- struct mmap_lgdr *mlgdr;
- int status = 0;
-
- newproc = dynalloc(sizeof(*newproc));
- if (newproc == NULL)
- return -ENOMEM;
-
- mlgdr = dynalloc(sizeof(*mlgdr));
- if (mlgdr == NULL)
- return -ENOMEM;
+ struct timespec ts;
+ struct timer tmr;
+ size_t timeout_msec;
+ tmrr_status_t status;
+ int error;
- memset(newproc, 0, sizeof(*newproc));
- status = md_fork(newproc, cur, (uintptr_t)ip);
- if (status != 0)
- goto done;
+ error = copyin((void *)scargs->arg0, &ts, sizeof(ts));
+ if (error < 0) {
+ return error;
+ }
- /* Set proc output if we can */
- if (newprocp != NULL)
- *newprocp = newproc;
+ if (ts.tv_nsec >= 1000000000) {
+ return -EINVAL;
+ }
- /* Initialize the mmap ledger */
- mlgdr->nbytes = 0;
- RBT_INIT(lgdr_entries, &mlgdr->hd);
- newproc->mlgdr = mlgdr;
+ status = req_timer(TIMER_GP, &tmr);
+ if (__unlikely(status != TMRR_SUCCESS)) {
+ return -ENOTSUP;
+ }
+ if (__unlikely(tmr.msleep == NULL)) {
+ return -ENOTSUP;
+ }
- newproc->pid = ++nthreads;
- signals_init(newproc);
- sched_enqueue_td(newproc);
-done:
- if (status != 0)
- dynfree(newproc);
+ timeout_msec = ts.tv_nsec / 1000000;
+ timeout_msec += ts.tv_sec * 1000;
- return status;
+ 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 caa0766..bc7f8b0 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -36,7 +36,9 @@
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_DEVFS, &g_devfs_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 7419d1d..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;
@@ -143,11 +184,12 @@ namei_mp_search(struct mount *mp, const char *path)
status = vfs_vop_lookup(vp, &lookup_args);
dynfree(name);
- if (status == 0)
- return vp;
+ if (status != 0) {
+ return NULL;
+ }
}
- return NULL;
+ return vp;
}
/*
@@ -211,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 6f2d683..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;
@@ -54,11 +54,11 @@ vfs_dostat(const char *path, struct stat *sbuf)
return -EINVAL;
}
- if ((copyinstr(path, pathbuf, sizeof(path))) < 0) {
+ if ((copyinstr(path, pathbuf, sizeof(pathbuf))) < 0) {
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);
+}