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/init_main.c42
-rw-r--r--sys/kern/kern_descrip.c11
-rw-r--r--sys/kern/kern_exec.c2
-rw-r--r--sys/kern/kern_exit.c69
-rw-r--r--sys/kern/kern_instl.c323
-rw-r--r--sys/kern/kern_sched.c67
-rw-r--r--sys/kern/kern_spawn.c28
-rw-r--r--sys/kern/kern_stub.c6
-rw-r--r--sys/kern/kern_syslog.c120
10 files changed, 678 insertions, 54 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/init_main.c b/sys/kern/init_main.c
index ff965bd..123a91d 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,7 @@
#include <vm/vm.h>
#include <string.h>
-static struct proc proc0;
+struct proc g_proc0;
static void
copyright(void)
@@ -52,6 +53,18 @@ copyright(void)
"Copyright (c) 2023-2025 Ian Marco Moffett and the OSMORA team\n");
}
+#if defined(_INSTALL_MEDIA)
+static void
+begin_install(void)
+{
+ struct cpu_info *ci;
+
+ ci = this_cpu();
+ ci->curtd = &g_proc0;
+ hyra_install();
+}
+#endif
+
static void
start_init(void)
{
@@ -84,11 +97,6 @@ main(void)
kprintf("Starting Hyra/%s v%s: %s\n", HYRA_ARCH, HYRA_VERSION,
HYRA_BUILDDATE);
-#if _INSTALL_MEDIA
- kprintf("Hyra install media detected\n");
- kprintf("Reform Industry!\n");
-#endif /* _INSTALL_MEDIA */
-
/* Start the ACPI subsystem */
acpi_init();
@@ -107,17 +115,29 @@ main(void)
md_intoff();
sched_init();
- memset(&proc0, 0, sizeof(proc0));
+ memset(&g_proc0, 0, sizeof(g_proc0));
/* Startup pid 1 */
- spawn(&proc0, start_init, NULL, 0, NULL);
-
- /* Load all drivers */
+ spawn(&g_proc0, start_init, NULL, 0, NULL);
md_inton();
+
+ /* Load all early drivers */
DRIVERS_INIT();
- /* Bootstrap APs and here we go! */
+#if defined(_INSTALL_MEDIA)
+ kprintf("Hyra install media detected\n");
+ kprintf("Reform Industry!\n");
+ begin_install();
+#endif
+
+ 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..1992d46 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -187,6 +187,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,16 +206,26 @@ 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;
}
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index bf6a26e..b760912 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 */
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index d6c9168..b6cbc4e 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,48 +78,62 @@ unload_td(struct proc *td)
}
}
+void
+proc_reap(struct proc *td)
+{
+ struct pcb *pcbp;
+ uintptr_t stack;
+
+ pcbp = &td->pcb;
+ stack = td->stack_base;
+
+ /*
+ * 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;
+ }
+
+ 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);
+}
+
/*
* 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);
+ 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);
-
/*
* Only free the process structure if we aren't
* being waited on, otherwise let it be so the
@@ -130,8 +149,17 @@ exit1(struct proc *td)
* 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();
+ if (td->data == NULL)
+ sched_enter();
+
+ sched_enqueue_td(parent);
+ parent->flags &= ~PROC_SLEEP;
sched_enter();
+ }
return 0;
}
@@ -144,7 +172,8 @@ sys_exit(struct syscall_args *scargs)
{
struct proc *td = this_td();
+ td->data = scargs->tf;
td->exit_status = scargs->arg0;
- exit1(td);
+ exit1(td, 0);
__builtin_unreachable();
}
diff --git a/sys/kern/kern_instl.c b/sys/kern/kern_instl.c
new file mode 100644
index 0000000..4f4d0f1
--- /dev/null
+++ b/sys/kern/kern_instl.c
@@ -0,0 +1,323 @@
+/*
+ * 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/systm.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/filedesc.h>
+#include <sys/fcntl.h>
+#include <sys/syslog.h>
+#include <sys/sio.h>
+#include <sys/vnode.h>
+#include <sys/disklabel.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/sched.h>
+#include <sys/reboot.h>
+#include <machine/cdefs.h>
+#include <vm/dynalloc.h>
+#include <vm/vm.h>
+#include <dev/timer.h>
+#include <assert.h>
+#include <string.h>
+
+#define DEFAULT_TIMEOUT 3
+#define YIELD_TIMEOUT 200000 /* In usec */
+#define BLOCK_SIZE 512
+#define BLOCK_THRESHOLD (BLOCK_SIZE * 1024)
+
+struct progress_bar {
+ bool dec;
+ uint8_t progress;
+};
+
+__used static struct timer tmr;
+__used static struct timer sched_timer;
+__used static struct sio_txn hdd_sio;
+
+#if defined(_INSTALL_MEDIA)
+__dead static void
+installer_quit(uint32_t seconds)
+{
+ kprintf("restarting in %d seconds...\n", seconds);
+ tmr.msleep(seconds * 1000);
+ cpu_reboot(REBOOT_RESET);
+ __builtin_unreachable();
+}
+
+static inline void
+installer_yield(void)
+{
+ md_inton();
+ sched_timer.oneshot_us(YIELD_TIMEOUT);
+ md_hlt();
+ md_intoff();
+}
+
+/*
+ * Throttle CPU usage by giving it small
+ * breaks based on the amount of data already
+ * read. The installer needs to perform very
+ * large block I/O operations and we want to
+ * avoid significant temperature spikes that
+ * would be kind of scary :(
+ *
+ * @n: Number of bytes read
+ */
+static void
+installer_throttle(size_t n)
+{
+ if ((n % BLOCK_THRESHOLD) == 0) {
+ installer_yield();
+ }
+}
+
+/*
+ * Create a progress bar animation for long
+ * operations.
+ *
+ * @bp: Pointer to a progress bar structure.
+ * @n: Number of blocks operated on.
+ * @max: Max blocks per bar update.
+ */
+static void
+progress_update(struct progress_bar *bp, size_t n, size_t max)
+{
+ const char CHR = '.';
+
+ /*
+ * We only want to update the progress bar
+ * per `max' blocks written.
+ */
+ if ((n > 0) && (n % max) != 0) {
+ return;
+ }
+
+ /* Add more '.' chars */
+ if (bp->progress < 8 && !bp->dec) {
+ kprintf(OMIT_TIMESTAMP "%c\f", CHR);
+ } else if (bp->progress >= 8) {
+ bp->dec = true;
+ }
+
+ /* Remove '.' chars */
+ if (bp->dec && bp->progress > 0) {
+ kprintf(OMIT_TIMESTAMP "\b\f");
+ } else if (bp->progress == 0) {
+ bp->dec = false;
+ }
+
+ if (!bp->dec) {
+ ++bp->progress;
+ } else {
+ --bp->progress;
+ }
+}
+
+static void
+installer_wipe(struct filedesc *hdd, uint32_t count)
+{
+ struct sio_txn sio;
+ struct progress_bar bar = {0, 0};
+ size_t write_len, total_blocks;
+ size_t write_blocks;
+ char buf[BLOCK_SIZE * 2];
+
+ write_len = sizeof(buf);
+ memset(buf, 0, write_len);
+ write_blocks = write_len / BLOCK_SIZE;
+
+ total_blocks = ALIGN_UP(count, BLOCK_SIZE);
+ total_blocks /= BLOCK_SIZE;
+
+ if (__unlikely(total_blocks == 0)) {
+ kprintf("bad block size for /dev/sd1\n");
+ installer_quit(DEFAULT_TIMEOUT);
+ }
+
+ sio.buf = buf;
+ sio.offset = 0;
+ sio.len = write_len;
+
+ /* Zero that shit */
+ kprintf("zeroing %d blocks...\n", total_blocks);
+ for (int i = 0; i < total_blocks; i += write_blocks) {
+ vfs_vop_write(hdd->vp, &sio);
+ installer_throttle(sio.offset);
+ sio.offset += write_len;
+ progress_update(&bar, i, 1000);
+ }
+
+ /* Cool off then continue */
+ installer_yield();
+ hdd_sio.offset = 0;
+ kprintf(OMIT_TIMESTAMP "OK\n");
+ tmr.msleep(1000);
+}
+
+/*
+ * Write data to the drive.
+ *
+ * @hdd: HDD file descriptor
+ * @file: Optional source file descriptor
+ * @p: Data pointer
+ * @len: Length of data.
+ */
+static void
+installer_write(struct filedesc *hdd, struct filedesc *file, void *p, size_t len)
+{
+ size_t nblocks;
+ struct sio_txn sio;
+ struct progress_bar bar = {0, 0};
+ char buf[BLOCK_SIZE];
+
+ len = ALIGN_UP(len, BLOCK_SIZE);
+ nblocks = len / BLOCK_SIZE;
+
+ hdd_sio.len = BLOCK_SIZE;
+ hdd_sio.buf = (len < BLOCK_SIZE) ? buf : p;
+
+ sio.len = BLOCK_SIZE;
+ sio.offset = 0;
+ sio.buf = (len < BLOCK_SIZE) ? buf : p;
+
+ if (len < BLOCK_SIZE) {
+ memcpy(buf, p, len);
+ }
+
+ kprintf("writing %d block(s)...\n", nblocks);
+ for (size_t i = 0; i < nblocks; ++i) {
+ if (file != NULL) {
+ vfs_vop_read(file->vp, &sio);
+ }
+ vfs_vop_write(hdd->vp, &hdd_sio);
+ installer_throttle(hdd_sio.offset);
+
+ sio.offset += BLOCK_SIZE;
+ hdd_sio.offset += BLOCK_SIZE;
+ progress_update(&bar, i, 400);
+ }
+
+ kprintf(OMIT_TIMESTAMP "OK\n");
+}
+
+#endif
+
+int
+hyra_install(void)
+{
+#if defined(_INSTALL_MEDIA)
+ int fd, hdd_fd;
+ char buf[BLOCK_SIZE];
+ struct filedesc *fildes, *hdd_fildes;
+ struct disklabel label;
+ struct vop_getattr_args getattr_args;
+ struct vattr iso_attr;
+ size_t iso_size;
+ size_t nzeros = 0; /* Zero byte count */
+ tmrr_status_t tmr_error;
+
+ /* Needed for msleep() */
+ tmr_error = req_timer(TIMER_GP, &tmr);
+ if (__unlikely(tmr_error != TMRR_SUCCESS)) {
+ kprintf("could not fetch TIMER_GP\n");
+ installer_quit(DEFAULT_TIMEOUT);
+ }
+
+ /*
+ * Grab the scheduler timer since we can
+ * reasonably assume it has oneshot capability.
+ */
+ tmr_error = req_timer(TIMER_SCHED, &sched_timer);
+ if (__unlikely(tmr_error != TMRR_SUCCESS)) {
+ kprintf("could not fetch TIMER_SCHED\n");
+ installer_quit(DEFAULT_TIMEOUT);
+ }
+
+ kprintf("::::::::::::::::::::::::::::\n");
+ kprintf("::::: Hyra Installer ::::::\n");
+ kprintf("::::::::::::::::::::::::::::\n");
+ kprintf("!! DRIVE WILL BE WIPED !!\n");
+ tmr.msleep(5000);
+
+
+ /*
+ * See if the target drive exists
+ *
+ * XXX: As of now, we only support SATA drives
+ * as a target for the installer.
+ */
+ hdd_fd = fd_open("/dev/sd1", O_RDWR);
+ if (hdd_fd < 0) {
+ kprintf("could not open /dev/sd1\n");
+ installer_quit(DEFAULT_TIMEOUT);
+ }
+
+ kprintf("installing to /dev/sd1...\n");
+
+ fd = fd_open("/boot/Hyra.iso", O_RDONLY);
+ if (fd < 0) {
+ kprintf("could not open /boot/Hyra.iso (status=%d)\n", fd);
+ installer_quit(DEFAULT_TIMEOUT);
+ }
+
+ /* Get attributes */
+ fildes = fd_get(fd);
+ getattr_args.vp = fildes->vp;
+ getattr_args.res = &iso_attr;
+ vfs_vop_getattr(fildes->vp, &getattr_args);
+
+ /* Get the ISO size */
+ iso_size = ALIGN_UP(iso_attr.size, BLOCK_SIZE);
+
+ /*
+ * First, wipe part of the drive of any data.
+ * This is done by simply filling it with
+ * zeros.
+ */
+ hdd_fildes = fd_get(hdd_fd);
+ nzeros = iso_size + sizeof(struct disklabel);
+ nzeros += BLOCK_SIZE;
+ installer_wipe(hdd_fildes, nzeros);
+
+ /*
+ * Now since the drive is zerored, we can prep
+ * our data buffers to write the actual install.
+ */
+ label.magic = DISK_MAG;
+ label.sect_size = BLOCK_SIZE;
+ installer_write(hdd_fildes, fildes, buf, iso_size);
+ installer_write(hdd_fildes, NULL, &label, sizeof(label));
+
+ kprintf("Installation complete!\n");
+ kprintf("Please remove installation media\n");
+ installer_quit(5);
+#endif /* _INSTALL_MEDIA */
+ return 0;
+}
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
index 2fe0f32..8e456d2 100644
--- a/sys/kern/kern_sched.c
+++ b/sys/kern/kern_sched.c
@@ -104,12 +104,22 @@ 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;
+ }
+
+ TAILQ_REMOVE(&queue->q, td, link);
+ if (ISSET(td->flags, PROC_SLEEP)) {
+ continue;
+ }
+
+ spinlock_release(&tdq_lock);
+ return td;
}
/* We got nothing */
@@ -125,6 +135,10 @@ sched_enqueue_td(struct proc *td)
{
struct sched_queue *queue;
+ if (ISSET(td->flags, PROC_SLEEP)) {
+ return;
+ }
+
spinlock_acquire(&tdq_lock);
queue = &qlist[td->priority];
@@ -176,15 +190,31 @@ 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;
@@ -203,11 +233,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);
}
@@ -217,6 +243,7 @@ sched_switch(struct trapframe *tf)
void
sched_enter(void)
{
+ md_inton();
sched_oneshot(false);
for (;;) {
md_pause();
@@ -226,12 +253,20 @@ 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;
+ ci->curtd = NULL;
+
+ md_inton();
+ sched_oneshot(false);
+ md_hlt();
+ ci->curtd = td;
}
void
diff --git a/sys/kern/kern_spawn.c b/sys/kern/kern_spawn.c
index cb898dc..4105668 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>
@@ -70,7 +71,7 @@ spawn_thunk(void)
char *envp[] = { NULL };
cur = this_td();
- args = cur->spawn_data;
+ args = cur->data;
path = args->path;
memcpy(pathbuf, path, strlen(path));
@@ -84,7 +85,7 @@ spawn_thunk(void)
if (execve(cur, &execve_args) != 0) {
pr_error("execve failed, aborting\n");
- exit1(this_td());
+ exit1(this_td(), 0);
}
__builtin_unreachable();
}
@@ -110,6 +111,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,7 +152,7 @@ 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;
/* Initialize the mmap ledger */
mlgdr->nbytes = 0;
@@ -160,7 +162,25 @@ spawn(struct proc *cur, void(*func)(void), void *p, int flags, struct proc **new
newproc->pid = ++nthreads;
signals_init(newproc);
sched_enqueue_td(newproc);
- return newproc->pid;
+ pid = newproc->pid;
+
+ if (ISSET(flags, SPAWN_WAIT)) {
+ newproc->flags |= PROC_WAITED;
+ cur->flags |= PROC_SLEEP;
+
+ while (ISSET(cur->flags, PROC_SLEEP)) {
+ sched_yield();
+ }
+
+ if (!ISSET(newproc->flags, PROC_ZOMB)) {
+ pr_error("spawn: fatal: %d not zombie\n", newproc->pid);
+ panic("possibly memory corruption\n");
+ }
+
+ proc_reap(newproc);
+ }
+
+ return pid;
}
/*
diff --git a/sys/kern/kern_stub.c b/sys/kern/kern_stub.c
index 1a5fb0e..fa1be65 100644
--- a/sys/kern/kern_stub.c
+++ b/sys/kern/kern_stub.c
@@ -41,7 +41,7 @@ sigfpe_default(int signo)
td = this_td();
kprintf("Floating point exception (pid=%d)\n", td->pid);
- exit1(td);
+ exit1(td, 0);
}
void
@@ -51,7 +51,7 @@ sigkill_default(int signo)
td = this_td();
kprintf("Terminated (pid=%d)\n", td->pid);
- exit1(td);
+ exit1(td, 0);
}
void
@@ -61,7 +61,7 @@ sigsegv_default(int signo)
td = this_td();
kprintf("Segmentation fault (pid=%d)\n", td->pid);
- exit1(td);
+ exit1(td, 0);
}
int
diff --git a/sys/kern/kern_syslog.c b/sys/kern/kern_syslog.c
index 656362e..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,8 +45,78 @@
#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)
@@ -58,6 +133,17 @@ syslog_write(const char *s, size_t len)
}
}
+ 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);
}
@@ -116,3 +202,37 @@ kprintf(const char *fmt, ...)
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
+};