summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/aarch64/aarch64/pmap.c21
-rw-r--r--sys/arch/aarch64/conf/GENERIC5
-rw-r--r--sys/arch/aarch64/conf/link.ld6
-rw-r--r--sys/arch/amd64/amd64/hpet.c16
-rw-r--r--sys/arch/amd64/amd64/intr.c7
-rw-r--r--sys/arch/amd64/amd64/machdep.c52
-rw-r--r--sys/arch/amd64/amd64/mp.c28
-rw-r--r--sys/arch/amd64/amd64/pmap.c36
-rw-r--r--sys/arch/amd64/amd64/proc_machdep.c24
-rw-r--r--sys/arch/amd64/amd64/trap.c35
-rw-r--r--sys/arch/amd64/amd64/vector.S126
-rw-r--r--sys/arch/amd64/conf/GENERIC13
-rw-r--r--sys/arch/amd64/conf/link.ld6
-rw-r--r--sys/dev/acpi/uacpi.c13
-rw-r--r--sys/dev/ic/ahci.c2
-rw-r--r--sys/dev/usb/xhci.c12
-rw-r--r--sys/dev/video/fbdev.c42
-rw-r--r--sys/fs/devfs.c9
-rw-r--r--sys/include/arch/amd64/cdefs.h9
-rw-r--r--sys/include/arch/amd64/cpu.h8
-rw-r--r--sys/include/dev/timer.h1
-rw-r--r--sys/include/dev/video/fbdev.h1
-rw-r--r--sys/include/sys/device.h5
-rw-r--r--sys/include/sys/disklabel.h4
-rw-r--r--sys/include/sys/driver.h61
-rw-r--r--sys/include/sys/limits.h4
-rw-r--r--sys/include/sys/proc.h8
-rw-r--r--sys/include/sys/sched.h2
-rw-r--r--sys/include/sys/spawn.h3
-rw-r--r--sys/include/sys/syslog.h2
-rw-r--r--sys/include/sys/systm.h2
-rw-r--r--sys/include/sys/vnode.h3
-rw-r--r--sys/include/vm/pmap.h11
-rw-r--r--sys/include/vm/vm_device.h43
-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
-rw-r--r--sys/vm/vm_device.c78
-rw-r--r--sys/vm/vm_map.c77
-rw-r--r--sys/vm/vm_vnode.c1
47 files changed, 1344 insertions, 164 deletions
diff --git a/sys/arch/aarch64/aarch64/pmap.c b/sys/arch/aarch64/aarch64/pmap.c
index b5ebda9..7e93959 100644
--- a/sys/arch/aarch64/aarch64/pmap.c
+++ b/sys/arch/aarch64/aarch64/pmap.c
@@ -66,3 +66,24 @@ pmap_destroy_vas(struct vas vas)
/* TODO: STUB */
return;
}
+
+bool
+pmap_is_clean(struct vas vas, vaddr_t va)
+{
+ /* TODO: STUB */
+ return false;
+}
+
+void
+pmap_mark_clean(struct vas vas, vaddr_t va)
+{
+ /* TODO: STUB */
+ return;
+}
+
+int
+pmap_set_cache(struct vas vas, vaddr_t va, int type)
+{
+ /* TODO: STUB */
+ return 0;
+}
diff --git a/sys/arch/aarch64/conf/GENERIC b/sys/arch/aarch64/conf/GENERIC
index 5691685..a716ac2 100644
--- a/sys/arch/aarch64/conf/GENERIC
+++ b/sys/arch/aarch64/conf/GENERIC
@@ -1,5 +1,6 @@
// Kernel options
-option SERIAL_DEBUG yes
+option SERIAL_DEBUG yes // Enable kmsg serial logging
+option USER_KMSG yes // Show kmsg in user consoles
// Kernel constants
-setval SCHED_NQUEUE 4
+setval SCHED_NQUEUE 4 // Number of scheduler queues (for MLFQ)
diff --git a/sys/arch/aarch64/conf/link.ld b/sys/arch/aarch64/conf/link.ld
index c64cec3..2aa8c93 100644
--- a/sys/arch/aarch64/conf/link.ld
+++ b/sys/arch/aarch64/conf/link.ld
@@ -40,6 +40,12 @@ SECTIONS
__drivers_init_end = .;
} :rodata
+ .drivers.defer : {
+ __driversd_init_start = .;
+ *(.drivers.defer .drivers.defer)
+ __driversd_init_end = .;
+ } :rodata
+
/* Move to the next memory page for .data */
. += CONSTANT(MAXPAGESIZE);
diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c
index 1670546..3b0ca46 100644
--- a/sys/arch/amd64/amd64/hpet.c
+++ b/sys/arch/amd64/amd64/hpet.c
@@ -47,6 +47,7 @@
#define CAP_CLK_PERIOD(caps) (caps >> 32)
#define FSEC_PER_SECOND 1000000000000000ULL
+#define NSEC_PER_SECOND 1000000000ULL
#define USEC_PER_SECOND 1000000ULL
static void *hpet_base = NULL;
@@ -135,6 +136,20 @@ hpet_time_usec(void)
}
static size_t
+hpet_time_nsec(void)
+{
+ uint64_t period, freq, caps;
+ uint64_t counter;
+
+ caps = hpet_read(HPET_REG_CAPS);
+ period = CAP_CLK_PERIOD(caps);
+ freq = FSEC_PER_SECOND / period;
+
+ counter = hpet_read(HPET_REG_MAIN_COUNTER);
+ return (counter * NSEC_PER_SECOND) / freq;
+}
+
+static size_t
hpet_time_sec(void)
{
return hpet_time_usec() / USEC_PER_SECOND;
@@ -180,6 +195,7 @@ hpet_init(void)
timer.usleep = hpet_usleep;
timer.nsleep = hpet_nsleep;
timer.get_time_usec = hpet_time_usec;
+ timer.get_time_nsec = hpet_time_nsec;
timer.get_time_sec = hpet_time_sec;
register_timer(TIMER_GP, &timer);
return 0;
diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c
index 1529b1c..9f70e88 100644
--- a/sys/arch/amd64/amd64/intr.c
+++ b/sys/arch/amd64/amd64/intr.c
@@ -96,11 +96,12 @@ intr_register(const char *name, const struct intr_hand *ih)
* Try to allocate an interrupt vector. An IPL is made up
* of 4 bits so there can be 16 vectors per IPL.
*
- * XXX: Vector 0x20 is reserved for the Hyra scheduler and
- * vector 0x21 is reserved for the CPU halt IPI.
+ * XXX: Vector 0x20 is reserved for the Hyra scheduler,
+ * vector 0x21 is reserved for the CPU halt IPI,
+ * and vector 0x22 is reserved for TLB shootdowns.
*/
for (int i = vec; i < vec + 16; ++i) {
- if (g_intrs[i] != NULL || i < 0x22) {
+ if (g_intrs[i] != NULL || i < 0x23) {
continue;
}
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 3381437..c6fb6c4 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -42,9 +42,11 @@
#include <machine/uart.h>
#include <machine/sync.h>
#include <machine/intr.h>
+#include <machine/cdefs.h>
#include <machine/isa/i8042var.h>
#define HALT_VECTOR 0x21
+#define TLB_VECTOR 0x22
#if defined(__SPECTRE_IBRS)
#define SPECTRE_IBRS __SPECTRE_IBRS
@@ -52,8 +54,6 @@
#define SPECTRE_IBRS 0
#endif
-static uint8_t halt_vector = 0;
-
int ibrs_enable(void);
void syscall_isr(void);
void pin_isr_load(void);
@@ -68,6 +68,31 @@ cpu_halt_isr(void *p)
__builtin_unreachable();
}
+__attribute__((__interrupt__))
+static void
+tlb_shootdown_isr(void *p)
+{
+ struct cpu_info *ci;
+ int ipl;
+
+ /*
+ * Get the current CPU and check if we even
+ * need a shootdown. If `tlb_shootdown' is
+ * unset, this is not for us.
+ */
+ ci = this_cpu();
+ if (!ci->tlb_shootdown) {
+ return;
+ }
+
+ ipl = splraise(IPL_HIGH);
+ __invlpg(ci->shootdown_va);
+
+ ci->shootdown_va = 0;
+ ci->tlb_shootdown = 0;
+ splx(ipl);
+}
+
static void
setup_vectors(void)
{
@@ -85,6 +110,7 @@ setup_vectors(void)
idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0);
idt_set_desc(0x80, IDT_USER_INT_GATE, ISR(syscall_isr), 0);
idt_set_desc(HALT_VECTOR, IDT_INT_GATE, ISR(cpu_halt_isr), 0);
+ idt_set_desc(TLB_VECTOR, IDT_INT_GATE, ISR(tlb_shootdown_isr), 0);
pin_isr_load();
}
@@ -130,6 +156,26 @@ backtrace_addr_to_name(uintptr_t addr, off_t *off)
}
void
+cpu_shootdown_tlb(vaddr_t va)
+{
+ uint32_t ncpu = cpu_count();
+ struct cpu_info *cip;
+
+ for (uint32_t i = 0; i < ncpu; ++i) {
+ cip = cpu_get(i);
+ if (cip == NULL) {
+ break;
+ }
+
+ spinlock_acquire(&cip->lock);
+ cip->shootdown_va = va;
+ cip->tlb_shootdown = 1;
+ lapic_send_ipi(cip->apicid, IPI_SHORTHAND_NONE, TLB_VECTOR);
+ spinlock_release(&cip->lock);
+ }
+}
+
+void
md_backtrace(void)
{
uintptr_t *rbp;
@@ -166,7 +212,7 @@ cpu_halt_all(void)
}
/* Send IPI to all cores */
- lapic_send_ipi(0, IPI_SHORTHAND_ALL, halt_vector);
+ lapic_send_ipi(0, IPI_SHORTHAND_ALL, HALT_VECTOR);
for (;;);
}
diff --git a/sys/arch/amd64/amd64/mp.c b/sys/arch/amd64/amd64/mp.c
index 22561d7..1e6d8d9 100644
--- a/sys/arch/amd64/amd64/mp.c
+++ b/sys/arch/amd64/amd64/mp.c
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/limine.h>
+#include <sys/limits.h>
#include <sys/syslog.h>
#include <sys/spinlock.h>
#include <sys/sched.h>
@@ -45,7 +46,9 @@ static volatile struct limine_smp_request g_smp_req = {
.revision = 0
};
-static volatile uint32_t ncpu_up = 0;
+static volatile uint32_t ncpu_up = 1;
+static struct cpu_info *ci_list[CPU_MAX];
+static struct spinlock ci_list_lock = {0};
static void
ap_trampoline(struct limine_smp_info *si)
@@ -57,11 +60,31 @@ ap_trampoline(struct limine_smp_info *si)
memset(ci, 0, sizeof(*ci));
cpu_startup(ci);
+ spinlock_acquire(&ci_list_lock);
+ ci_list[ncpu_up] = ci;
+ spinlock_release(&ci_list_lock);
+
atomic_inc_int(&ncpu_up);
sched_enter();
while (1);
}
+struct cpu_info *
+cpu_get(uint32_t index)
+{
+ if (index >= ncpu_up) {
+ return NULL;
+ }
+
+ return ci_list[index];
+}
+
+uint32_t
+cpu_count(void)
+{
+ return ncpu_up;
+}
+
void
mp_bootstrap_aps(struct cpu_info *ci)
{
@@ -74,6 +97,7 @@ mp_bootstrap_aps(struct cpu_info *ci)
cpus = resp->cpus;
cpu_init_counter = resp->cpu_count - 1;
+ ci_list[0] = ci;
if (resp->cpu_count == 1) {
pr_trace("CPU has 1 core, no APs to bootstrap...\n");
@@ -91,5 +115,5 @@ mp_bootstrap_aps(struct cpu_info *ci)
}
/* Wait for all cores to be ready */
- while (ncpu_up < cpu_init_counter);
+ while ((ncpu_up - 1) < cpu_init_counter);
}
diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c
index 2e62a4b..0bdf3b7 100644
--- a/sys/arch/amd64/amd64/pmap.c
+++ b/sys/arch/amd64/amd64/pmap.c
@@ -33,6 +33,8 @@
#include <sys/errno.h>
#include <machine/tlb.h>
#include <machine/vas.h>
+#include <machine/cpu.h>
+#include <machine/cdefs.h>
#include <vm/pmap.h>
#include <vm/physmem.h>
#include <vm/vm.h>
@@ -303,3 +305,37 @@ pmap_set_cache(struct vas vas, vaddr_t va, int type)
return 0;
}
+
+bool
+pmap_is_clean(struct vas vas, vaddr_t va)
+{
+ uintptr_t *tbl;
+ int status;
+ size_t idx;
+
+ if ((status = pmap_get_tbl(vas, va, false, &tbl)) != 0)
+ return status;
+
+ idx = pmap_get_level_index(1, va);
+ return ISSET(tbl[idx], PTE_DIRTY) == 0;
+}
+
+void
+pmap_mark_clean(struct vas vas, vaddr_t va)
+{
+ uintptr_t *tbl;
+ int status;
+ size_t idx;
+
+ if ((status = pmap_get_tbl(vas, va, false, &tbl)) != 0)
+ return;
+
+ idx = pmap_get_level_index(1, va);
+ tbl[idx] &= ~PTE_DIRTY;
+
+ if (cpu_count() > 1) {
+ cpu_shootdown_tlb(va);
+ } else {
+ __invlpg(va);
+ }
+}
diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c
index 9579b7e..4fe8580 100644
--- a/sys/arch/amd64/amd64/proc_machdep.c
+++ b/sys/arch/amd64/amd64/proc_machdep.c
@@ -123,24 +123,37 @@ md_td_kick(struct proc *td)
{
struct trapframe *tfp;
struct cpu_info *ci;
+ uint8_t rpl;
+ uint16_t ds = KERNEL_DS;
tfp = &td->tf;
+ rpl = tfp->cs & 3;
ci = this_cpu();
ci->curtd = td;
+ if (rpl == 3) {
+ td->flags &= ~PROC_KTD;
+ ds = USER_DS | 3;
+ }
+
__ASMV(
- "push %0\n"
+ "mov %0, %%rax\n"
"push %1\n"
- "pushf\n"
"push %2\n"
"push %3\n"
+ "push %%rax\n"
+ "push %4\n"
+ "test $3, %%ax\n"
+ "jz 1f\n"
"lfence\n"
"swapgs\n"
- "iretq"
+ "1:\n"
+ " iretq"
:
- : "i" (USER_DS | 3),
+ : "r" (tfp->cs),
+ "r" (ds),
"r" (tfp->rsp),
- "i" (USER_CS | 3),
+ "m" (tfp->rflags),
"r" (tfp->rip)
);
@@ -201,6 +214,7 @@ md_spawn(struct proc *p, struct proc *parent, uintptr_t ip)
*/
if (rpl == 0) {
stack_base += VM_HIGHER_HALF;
+ p->flags |= PROC_KTD;
} else {
vm_map(pcbp->addrsp, stack_base, stack_base,
PROT_READ | PROT_WRITE | PROT_USER, PROC_STACK_PAGES);
diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c
index 6492a29..84a6a77 100644
--- a/sys/arch/amd64/amd64/trap.c
+++ b/sys/arch/amd64/amd64/trap.c
@@ -60,6 +60,17 @@ static const char *trap_type[] = {
[TRAP_SS] = "stack-segment fault"
};
+/* Page-fault flags */
+static const char pf_flags[] = {
+ 'p', /* Present */
+ 'w', /* Write */
+ 'u', /* User */
+ 'r', /* Reserved write */
+ 'x', /* Instruction fetch */
+ 'k', /* Protection key violation */
+ 's' /* Shadow stack access */
+};
+
static inline uintptr_t
pf_faultaddr(void)
{
@@ -69,6 +80,23 @@ pf_faultaddr(void)
}
static void
+pf_code(uint64_t error_code)
+{
+ char tab[8] = {
+ '-', '-', '-',
+ '-', '-', '-',
+ '-', '\0'
+ };
+
+ for (int i = 0; i < 7; ++i) {
+ if (ISSET(error_code, BIT(i))) {
+ tab[i] = pf_flags[i];
+ }
+ }
+ kprintf("code=[%s]\n", tab);
+}
+
+static void
regdump(struct trapframe *tf)
{
uintptr_t cr3, cr2 = pf_faultaddr();
@@ -79,6 +107,10 @@ regdump(struct trapframe *tf)
: "memory"
);
+ if (tf->trapno == TRAP_PAGEFLT) {
+ pf_code(tf->error_code);
+ }
+
kprintf(OMIT_TIMESTAMP
"RAX=%p RCX=%p RDX=%p\n"
"RBX=%p RSI=%p RDI=%p\n"
@@ -101,6 +133,9 @@ trap_user(struct trapframe *tf)
switch (tf->trapno) {
case TRAP_PROTFLT:
case TRAP_PAGEFLT:
+ if (tf->trapno == TRAP_PAGEFLT) {
+ pf_code(tf->error_code);
+ }
sigaddset(&sigset, SIGSEGV);
break;
case TRAP_ARITH_ERR:
diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S
index 32ccd34..d2a3d89 100644
--- a/sys/arch/amd64/amd64/vector.S
+++ b/sys/arch/amd64/amd64/vector.S
@@ -64,69 +64,69 @@ done:
.globl pin_isr_load
pin_isr_load:
- IDT_SET_VEC 34, ioapic_edge_0
- IDT_SET_VEC 35, ioapic_edge_1
- IDT_SET_VEC 36, ioapic_edge_2
- IDT_SET_VEC 37, ioapic_edge_3
- IDT_SET_VEC 38, ioapic_edge_4
- IDT_SET_VEC 39, ioapic_edge_5
- IDT_SET_VEC 40, ioapic_edge_6
- IDT_SET_VEC 41, ioapic_edge_7
- IDT_SET_VEC 42, ioapic_edge_8
- IDT_SET_VEC 43, ioapic_edge_9
- IDT_SET_VEC 44, ioapic_edge_10
- IDT_SET_VEC 45, ioapic_edge_11
- IDT_SET_VEC 46, ioapic_edge_12
- IDT_SET_VEC 47, ioapic_edge_13
- IDT_SET_VEC 48, ioapic_edge_14
- IDT_SET_VEC 49, ioapic_edge_15
- IDT_SET_VEC 50, ioapic_edge_16
- IDT_SET_VEC 51, ioapic_edge_17
- IDT_SET_VEC 52, ioapic_edge_18
- IDT_SET_VEC 53, ioapic_edge_19
- IDT_SET_VEC 54, ioapic_edge_20
- IDT_SET_VEC 55, ioapic_edge_21
- IDT_SET_VEC 56, ioapic_edge_22
- IDT_SET_VEC 57, ioapic_edge_23
- IDT_SET_VEC 58, ioapic_edge_24
- IDT_SET_VEC 59, ioapic_edge_25
- IDT_SET_VEC 60, ioapic_edge_26
- IDT_SET_VEC 61, ioapic_edge_27
- IDT_SET_VEC 62, ioapic_edge_28
- IDT_SET_VEC 63, ioapic_edge_29
- IDT_SET_VEC 64, ioapic_edge_30
- IDT_SET_VEC 65, ioapic_edge_31
- IDT_SET_VEC 66, ioapic_edge_32
- IDT_SET_VEC 67, ioapic_edge_33
- IDT_SET_VEC 68, ioapic_edge_34
- IDT_SET_VEC 69, ioapic_edge_35
- IDT_SET_VEC 70, ioapic_edge_36
- IDT_SET_VEC 71, ioapic_edge_37
- IDT_SET_VEC 72, ioapic_edge_38
- IDT_SET_VEC 73, ioapic_edge_39
- IDT_SET_VEC 74, ioapic_edge_40
- IDT_SET_VEC 75, ioapic_edge_41
- IDT_SET_VEC 76, ioapic_edge_42
- IDT_SET_VEC 77, ioapic_edge_43
- IDT_SET_VEC 78, ioapic_edge_44
- IDT_SET_VEC 79, ioapic_edge_45
- IDT_SET_VEC 80, ioapic_edge_46
- IDT_SET_VEC 81, ioapic_edge_47
- IDT_SET_VEC 82, ioapic_edge_48
- IDT_SET_VEC 83, ioapic_edge_49
- IDT_SET_VEC 84, ioapic_edge_50
- IDT_SET_VEC 85, ioapic_edge_51
- IDT_SET_VEC 86, ioapic_edge_52
- IDT_SET_VEC 87, ioapic_edge_53
- IDT_SET_VEC 88, ioapic_edge_54
- IDT_SET_VEC 89, ioapic_edge_55
- IDT_SET_VEC 90, ioapic_edge_56
- IDT_SET_VEC 91, ioapic_edge_57
- IDT_SET_VEC 92, ioapic_edge_58
- IDT_SET_VEC 93, ioapic_edge_59
- IDT_SET_VEC 94, ioapic_edge_60
- IDT_SET_VEC 95, ioapic_edge_61
- IDT_SET_VEC 96, ioapic_edge_62
+ IDT_SET_VEC 35, ioapic_edge_0
+ IDT_SET_VEC 36, ioapic_edge_1
+ IDT_SET_VEC 37, ioapic_edge_2
+ IDT_SET_VEC 38, ioapic_edge_3
+ IDT_SET_VEC 39, ioapic_edge_4
+ IDT_SET_VEC 40, ioapic_edge_5
+ IDT_SET_VEC 41, ioapic_edge_6
+ IDT_SET_VEC 42, ioapic_edge_7
+ IDT_SET_VEC 43, ioapic_edge_8
+ IDT_SET_VEC 44, ioapic_edge_9
+ IDT_SET_VEC 45, ioapic_edge_10
+ IDT_SET_VEC 46, ioapic_edge_11
+ IDT_SET_VEC 47, ioapic_edge_12
+ IDT_SET_VEC 48, ioapic_edge_13
+ IDT_SET_VEC 49, ioapic_edge_14
+ IDT_SET_VEC 50, ioapic_edge_15
+ IDT_SET_VEC 51, ioapic_edge_16
+ IDT_SET_VEC 52, ioapic_edge_17
+ IDT_SET_VEC 53, ioapic_edge_18
+ IDT_SET_VEC 54, ioapic_edge_19
+ IDT_SET_VEC 55, ioapic_edge_20
+ IDT_SET_VEC 56, ioapic_edge_21
+ IDT_SET_VEC 57, ioapic_edge_22
+ IDT_SET_VEC 58, ioapic_edge_23
+ IDT_SET_VEC 59, ioapic_edge_24
+ IDT_SET_VEC 60, ioapic_edge_25
+ IDT_SET_VEC 61, ioapic_edge_26
+ IDT_SET_VEC 62, ioapic_edge_27
+ IDT_SET_VEC 63, ioapic_edge_28
+ IDT_SET_VEC 64, ioapic_edge_29
+ IDT_SET_VEC 65, ioapic_edge_30
+ IDT_SET_VEC 66, ioapic_edge_31
+ IDT_SET_VEC 67, ioapic_edge_32
+ IDT_SET_VEC 68, ioapic_edge_33
+ IDT_SET_VEC 69, ioapic_edge_34
+ IDT_SET_VEC 70, ioapic_edge_35
+ IDT_SET_VEC 71, ioapic_edge_36
+ IDT_SET_VEC 72, ioapic_edge_37
+ IDT_SET_VEC 73, ioapic_edge_38
+ IDT_SET_VEC 74, ioapic_edge_39
+ IDT_SET_VEC 75, ioapic_edge_40
+ IDT_SET_VEC 76, ioapic_edge_41
+ IDT_SET_VEC 77, ioapic_edge_42
+ IDT_SET_VEC 78, ioapic_edge_43
+ IDT_SET_VEC 79, ioapic_edge_44
+ IDT_SET_VEC 80, ioapic_edge_45
+ IDT_SET_VEC 81, ioapic_edge_46
+ IDT_SET_VEC 82, ioapic_edge_47
+ IDT_SET_VEC 83, ioapic_edge_48
+ IDT_SET_VEC 84, ioapic_edge_49
+ IDT_SET_VEC 85, ioapic_edge_50
+ IDT_SET_VEC 86, ioapic_edge_51
+ IDT_SET_VEC 87, ioapic_edge_52
+ IDT_SET_VEC 88, ioapic_edge_53
+ IDT_SET_VEC 89, ioapic_edge_54
+ IDT_SET_VEC 90, ioapic_edge_55
+ IDT_SET_VEC 91, ioapic_edge_56
+ IDT_SET_VEC 92, ioapic_edge_57
+ IDT_SET_VEC 93, ioapic_edge_58
+ IDT_SET_VEC 94, ioapic_edge_59
+ IDT_SET_VEC 95, ioapic_edge_60
+ IDT_SET_VEC 96, ioapic_edge_61
+ IDT_SET_VEC 97, ioapic_edge_62
IDT_SET_VEC 97, ioapic_edge_63
ret
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index db3ce4c..7a28038 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,9 +1,16 @@
+//
// Kernel options
-option SPECTRE_IBRS no
-option SERIAL_DEBUG yes
+//
+// XXX: Indirect branch restricted speculation (SPECTRE_IBRS)
+// is disabled by default as it can lead to significant
+// performance degradation.
+//
+option SPECTRE_IBRS no // Enable the IBRS CPU feature
+option SERIAL_DEBUG yes // Enable kmsg serial logging
+option USER_KMSG no // Show kmsg in user consoles
// Kernel constants
-setval SCHED_NQUEUE 4
+setval SCHED_NQUEUE 4 // Number of scheduler queues (for MLFQ)
// Console attributes
setval CONSOLE_BG 0x000000
diff --git a/sys/arch/amd64/conf/link.ld b/sys/arch/amd64/conf/link.ld
index 9c47a81..a43824f 100644
--- a/sys/arch/amd64/conf/link.ld
+++ b/sys/arch/amd64/conf/link.ld
@@ -29,6 +29,12 @@ SECTIONS
__drivers_init_end = .;
} :rodata
+ .drivers.defer : {
+ __driversd_init_start = .;
+ *(.drivers.defer .drivers.defer)
+ __driversd_init_end = .;
+ } :rodata
+
. += CONSTANT(MAXPAGESIZE);
.data : {
diff --git a/sys/dev/acpi/uacpi.c b/sys/dev/acpi/uacpi.c
index 03d0ecf..612f23b 100644
--- a/sys/dev/acpi/uacpi.c
+++ b/sys/dev/acpi/uacpi.c
@@ -513,9 +513,18 @@ uacpi_u64
uacpi_kernel_get_nanoseconds_since_boot(void)
{
static uacpi_u64 time = 0;
+ static struct timer tmr = {0};
+ tmrr_status_t tmr_error;
+
+ if (time == 0) {
+ tmr_error = req_timer(TIMER_GP, &tmr);
+ if (tmr_error != TMRR_SUCCESS) {
+ time += 1000000;
+ return time;
+ }
+ }
- /* TODO */
- time += 1000000;
+ time = tmr.get_time_nsec();
return time;
}
diff --git a/sys/dev/ic/ahci.c b/sys/dev/ic/ahci.c
index d07acd7..905149e 100644
--- a/sys/dev/ic/ahci.c
+++ b/sys/dev/ic/ahci.c
@@ -1018,4 +1018,4 @@ static struct bdevsw ahci_bdevsw = {
.bsize = ahci_dev_bsize
};
-DRIVER_EXPORT(ahci_init);
+DRIVER_DEFER(ahci_init);
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index 9ab109a..5276eea 100644
--- a/sys/dev/usb/xhci.c
+++ b/sys/dev/usb/xhci.c
@@ -37,6 +37,7 @@
#include <dev/usb/xhciregs.h>
#include <dev/usb/xhcivar.h>
#include <dev/pci/pci.h>
+#include <dev/pci/pciregs.h>
#include <dev/acpi/acpi.h>
#include <vm/physmem.h>
#include <vm/dynalloc.h>
@@ -496,6 +497,16 @@ xhci_init_hc(struct xhci_hc *hc)
return 0;
}
+static void
+xhci_init_pci(void)
+{
+ uint32_t tmp;
+
+ tmp = pci_readl(hci_dev, PCIREG_CMDSTATUS);
+ tmp |= (PCI_BUS_MASTERING | PCI_MEM_SPACE);
+ pci_writel(hci_dev, PCIREG_CMDSTATUS, tmp);
+}
+
static int
xhci_init(void)
{
@@ -528,6 +539,7 @@ xhci_init(void)
return -ENODEV;
}
+ xhci_init_pci();
return xhci_init_hc(&xhc);
}
diff --git a/sys/dev/video/fbdev.c b/sys/dev/video/fbdev.c
index f21c769..391400c 100644
--- a/sys/dev/video/fbdev.c
+++ b/sys/dev/video/fbdev.c
@@ -29,16 +29,35 @@
#include <sys/types.h>
#include <sys/limine.h>
+#include <sys/device.h>
+#include <sys/driver.h>
#include <dev/video/fbdev.h>
+#include <fs/devfs.h>
+#include <vm/vm.h>
#define FRAMEBUFFER \
framebuffer_req.response->framebuffers[0]
+static struct cdevsw fb_cdevsw;
static volatile struct limine_framebuffer_request framebuffer_req = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 0
};
+static paddr_t
+fbdev_mmap(dev_t dev, off_t off, int flags)
+{
+ size_t max_bounds;
+
+ max_bounds = FRAMEBUFFER->pitch * FRAMEBUFFER->height;
+ max_bounds /= 4;
+ if (off > max_bounds) {
+ return 0;
+ }
+
+ return VIRT_TO_PHYS(FRAMEBUFFER->address);
+}
+
struct fbdev
fbdev_get(void)
{
@@ -51,3 +70,26 @@ fbdev_get(void)
ret.bpp = FRAMEBUFFER->bpp;
return ret;
}
+
+static int
+fbdev_init(void)
+{
+ char devname[] = "fb0";
+ devmajor_t major;
+ dev_t dev;
+
+ /* Register the device here */
+ major = dev_alloc_major();
+ dev = dev_alloc(major);
+ dev_register(major, dev, &fb_cdevsw);
+ devfs_create_entry(devname, major, dev, 0444);
+ return 0;
+}
+
+static struct cdevsw fb_cdevsw = {
+ .read = noread,
+ .write = nowrite,
+ .mmap = fbdev_mmap
+};
+
+DRIVER_EXPORT(fbdev_init);
diff --git a/sys/fs/devfs.c b/sys/fs/devfs.c
index 1dfc10d..0c087f0 100644
--- a/sys/fs/devfs.c
+++ b/sys/fs/devfs.c
@@ -127,6 +127,8 @@ devfs_lookup(struct vop_lookup_args *args)
vp->data = dnp;
vp->vops = &g_devfs_vops;
+ vp->major = dnp->major;
+ vp->dev = dnp->dev;
*args->vpp = vp;
return 0;
}
@@ -170,13 +172,6 @@ devfs_getattr(struct vop_getattr_args *args)
static int
devfs_reclaim(struct vnode *vp)
{
- struct devfs_node *dnp;
-
- if ((dnp = vp->data) != NULL) {
- dynfree(dnp->name);
- dynfree(vp->data);
- }
-
vp->data = NULL;
return 0;
}
diff --git a/sys/include/arch/amd64/cdefs.h b/sys/include/arch/amd64/cdefs.h
index bab0c89..0a20324 100644
--- a/sys/include/arch/amd64/cdefs.h
+++ b/sys/include/arch/amd64/cdefs.h
@@ -43,4 +43,13 @@
#define md_inton() __ASMV("sti") /* Enable interrupts */
#define md_hlt() __ASMV("hlt") /* Halt the processor */
+/*
+ * AMD64 specific defines
+ */
+#define __invlpg(VA) \
+ __ASMV("invlpg %0" \
+ : \
+ : "m" ((VA)) \
+ : "memory")
+
#endif /* !_AMD64_CDEFS_H_ */
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index dd753b7..2d08d6e 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/proc.h>
+#include <sys/spinlock.h>
#include <machine/tss.h>
#define CPU_IRQ(IRQ_N) (BIT((IRQ_N)) & 0xFF)
@@ -40,11 +41,14 @@
struct cpu_info {
uint32_t apicid;
uint8_t has_x2apic : 1;
+ uint8_t tlb_shootdown : 1;
uint8_t ipl;
size_t lapic_tmr_freq;
uint8_t irq_mask;
+ vaddr_t shootdown_va;
struct tss_entry *tss;
struct proc *curtd;
+ struct spinlock lock;
struct cpu_info *self;
};
@@ -52,6 +56,10 @@ __dead void cpu_halt_all(void);
void cpu_halt_others(void);
void cpu_startup(struct cpu_info *ci);
+struct cpu_info *cpu_get(uint32_t index);
+uint32_t cpu_count(void);
+void cpu_shootdown_tlb(vaddr_t va);
+
struct cpu_info *this_cpu(void);
void mp_bootstrap_aps(struct cpu_info *ci);
diff --git a/sys/include/dev/timer.h b/sys/include/dev/timer.h
index e54adcc..fe91323 100644
--- a/sys/include/dev/timer.h
+++ b/sys/include/dev/timer.h
@@ -69,6 +69,7 @@ struct timer {
const char *name; /* e.g "HPET" */
size_t(*calibrate)(void); /* Returns frequency, 0 for unspecified */
size_t(*get_time_usec)(void); /* Time since init (microseconds) */
+ size_t(*get_time_nsec)(void); /* Time since init (nanoseconds) */
size_t(*get_time_sec)(void); /* Time since init (seconds) */
int(*msleep)(size_t ms);
int(*usleep)(size_t us);
diff --git a/sys/include/dev/video/fbdev.h b/sys/include/dev/video/fbdev.h
index c80fd92..c9fec94 100644
--- a/sys/include/dev/video/fbdev.h
+++ b/sys/include/dev/video/fbdev.h
@@ -52,5 +52,6 @@ fbdev_get_index(const struct fbdev *fbdev, uint32_t x, uint32_t y)
}
struct fbdev fbdev_get(void);
+void fbdev_init_dev(void);
#endif /* !_DEV_FBDEV_H_ */
diff --git a/sys/include/sys/device.h b/sys/include/sys/device.h
index fcafdab..cb2a702 100644
--- a/sys/include/sys/device.h
+++ b/sys/include/sys/device.h
@@ -36,6 +36,7 @@
#include <sys/queue.h>
#include <sys/proc.h>
#include <sys/sio.h>
+#include <vm/vm_obj.h>
typedef uint8_t devmajor_t;
@@ -47,6 +48,10 @@ typedef int(*dev_bsize_t)(dev_t);
struct cdevsw {
int(*read)(dev_t dev, struct sio_txn *sio, int flags);
int(*write)(dev_t dev, struct sio_txn *sio, int flags);
+ paddr_t(*mmap)(dev_t dev, off_t off, int flags);
+
+ /* Private */
+ struct vm_object vmobj;
};
struct bdevsw {
diff --git a/sys/include/sys/disklabel.h b/sys/include/sys/disklabel.h
index d1e160b..895c35e 100644
--- a/sys/include/sys/disklabel.h
+++ b/sys/include/sys/disklabel.h
@@ -35,8 +35,10 @@
#define DISK_MAG 0x4F445421UL /* "ODT!" */
/*
+ * Represents a disk table.
+ *
* @magic: Magic number (`DISK_MAG')
- * @sect_size: Sector size
+ * @sect_size: Disk sector size
*/
struct disklabel {
uint32_t magic;
diff --git a/sys/include/sys/driver.h b/sys/include/sys/driver.h
index 05c40fa..8ab9521 100644
--- a/sys/include/sys/driver.h
+++ b/sys/include/sys/driver.h
@@ -31,27 +31,88 @@
#define _SYS_DRIVER_H_
#include <sys/cdefs.h>
+#include <sys/proc.h>
+#include <sys/types.h>
#if defined(_KERNEL)
+/* Variable driver data */
+struct driver_var {
+ uint8_t deferred : 1;
+};
+
struct driver {
int(*init)(void);
+ struct driver_var *data;
};
+extern struct proc g_proc0;
+
+/* Early (high priority) drivers */
extern char __drivers_init_start[];
extern char __drivers_init_end[];
+/* Deferred (low priority) drivers */
+extern char __driversd_init_start[];
+extern char __driversd_init_end[];
+
#define DRIVER_EXPORT(INIT) \
+ static struct driver_var __driver_var = { \
+ .deferred = 0 \
+ }; \
+ \
__attribute__((used, section(".drivers"))) \
static struct driver __driver_desc = { \
.init = INIT, \
+ .data = &__driver_var \
+ }
+
+/*
+ * Some drivers are not required to start up
+ * early for proper system operation and may
+ * be deferred to start at a later time.
+ *
+ * Examples of such (deferrable) drivers include code
+ * that waits for I/O (e.g., disks, network cards,
+ * et cetera). This allows for faster boot times
+ * as only *required* drivers are started before
+ * everything else.
+ *
+ * Drivers that wish to be deferred may export themselves
+ * via the DRIVER_DEFER() macro. The DRIVER_DEFERRED()
+ * macro gives the value of 1 if the current driver
+ * context has yet to be initialized. The driver may
+ * use this to defer requests for I/O.
+ */
+#if !defined(_INSTALL_MEDIA)
+#define DRIVER_DEFER(INIT) \
+ static struct driver_var __driver_var = { \
+ .deferred = 1 \
+ }; \
+ \
+ __attribute__((used, section(".drivers.defer"))) \
+ static struct driver __driver_desc = { \
+ .init = INIT, \
+ .data = &__driver_var \
}
+#define DRIVER_DEFERRED() __driver_var.deferred
+#else
+#define DRIVER_DEFER(INIT) DRIVER_EXPORT(INIT)
+#define DRIVER_DEFERRED() 0
+#endif /* _INSTALL_MEDIA */
+
#define DRIVERS_INIT() \
for (struct driver *__d = (struct driver *)__drivers_init_start; \
(uintptr_t)__d < (uintptr_t)__drivers_init_end; ++__d) \
{ \
__d->init(); \
}
+
+#define DRIVERS_SCHED() \
+ spawn(&g_proc0, __driver_init_td, NULL, 0, NULL)
+
+void __driver_init_td(void);
+
#endif /* _KERNEL */
#endif /* !_SYS_DRIVER_H_ */
diff --git a/sys/include/sys/limits.h b/sys/include/sys/limits.h
index 6185719..198c963 100644
--- a/sys/include/sys/limits.h
+++ b/sys/include/sys/limits.h
@@ -33,5 +33,7 @@
#define PATH_MAX 1024
#define SSIZE_MAX 32767
#define CHAR_BIT 8
-
+#if defined(_KERNEL)
+#define CPU_MAX 256
+#endif /* _KERNEL */
#endif /* !_SYS_LIMITS_H_ */
diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h
index 1b59de9..25f5fd3 100644
--- a/sys/include/sys/proc.h
+++ b/sys/include/sys/proc.h
@@ -64,7 +64,7 @@ struct proc {
struct trapframe tf;
struct pcb pcb;
struct proc *parent;
- void *spawn_data;
+ void *data;
size_t priority;
int exit_status;
bool rested;
@@ -83,9 +83,13 @@ struct proc {
#define PROC_ZOMB BIT(2) /* Zombie (dead but not deallocated) */
#define PROC_LEAFQ BIT(3) /* Leaf queue is active */
#define PROC_WAITED BIT(4) /* Being waited on by parent */
+#define PROC_KTD BIT(5) /* Kernel thread */
+#define PROC_SLEEP BIT(6) /* Thread execution paused */
struct proc *this_td(void);
struct proc *get_child(struct proc *cur, pid_t pid);
+void proc_reap(struct proc *td);
+
int md_spawn(struct proc *p, struct proc *parent, uintptr_t ip);
scret_t sys_spawn(struct syscall_args *scargs);
@@ -95,7 +99,7 @@ void md_td_stackinit(struct proc *td, void *stack_top, struct exec_prog *prog);
__dead void md_td_kick(struct proc *td);
int fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp);
-int exit1(struct proc *td);
+int exit1(struct proc *td, int flags);
__dead scret_t sys_exit(struct syscall_args *scargs);
#endif /* _KERNEL */
diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h
index 80f4d1c..7d17607 100644
--- a/sys/include/sys/sched.h
+++ b/sys/include/sys/sched.h
@@ -37,6 +37,8 @@
void sched_init(void);
void sched_yield(void);
+
+void sched_switch_to(struct trapframe *tf, struct proc *td);
void sched_detach(struct proc *td);
__dead void sched_enter(void);
diff --git a/sys/include/sys/spawn.h b/sys/include/sys/spawn.h
index 3828d5c..9d823db 100644
--- a/sys/include/sys/spawn.h
+++ b/sys/include/sys/spawn.h
@@ -31,6 +31,9 @@
#define _SYS_SPAWN_H_
#include <sys/types.h>
+#include <sys/param.h>
+
+#define SPAWN_WAIT BIT(0)
#if !defined(_KERNEL)
pid_t spawn(const char *pathname, int flags);
diff --git a/sys/include/sys/syslog.h b/sys/include/sys/syslog.h
index defb341..b9d34ab 100644
--- a/sys/include/sys/syslog.h
+++ b/sys/include/sys/syslog.h
@@ -31,11 +31,13 @@
#define _SYS_SYSLOG_H_
#include <stdarg.h>
+#include <stdbool.h>
#if defined(_KERNEL)
#define OMIT_TIMESTAMP "\x01"
+void syslog_silence(bool option);
void kprintf(const char *fmt, ...);
void serial_init(void);
void serial_putc(char c);
diff --git a/sys/include/sys/systm.h b/sys/include/sys/systm.h
index 42e1723..5d06257 100644
--- a/sys/include/sys/systm.h
+++ b/sys/include/sys/systm.h
@@ -55,5 +55,7 @@ __sigraise(int signo)
dispatch_signals(td);
}
+int hyra_install(void);
+
#endif /* _KERNEL */
#endif /* !_SYS_SYSTM_H_ */
diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h
index 33092f9..cd71817 100644
--- a/sys/include/sys/vnode.h
+++ b/sys/include/sys/vnode.h
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/queue.h>
+#include <sys/vnode.h>
#include <sys/atomic.h>
#include <sys/sio.h>
#include <vm/vm_obj.h>
@@ -47,6 +48,8 @@ struct vnode {
const struct vops *vops;
struct vm_object vobj;
uint32_t refcount;
+ dev_t major;
+ dev_t dev;
TAILQ_ENTRY(vnode) vcache_link;
};
diff --git a/sys/include/vm/pmap.h b/sys/include/vm/pmap.h
index 9eed184..e1f3f89 100644
--- a/sys/include/vm/pmap.h
+++ b/sys/include/vm/pmap.h
@@ -76,6 +76,17 @@ int pmap_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot);
int pmap_unmap(struct vas vas, vaddr_t va);
/*
+ * Returns true if the page is clean (modified), otherwise
+ * returns false.
+ */
+bool pmap_is_clean(struct vas vas, vaddr_t va);
+
+/*
+ * Marks a page as clean (unmodified)
+ */
+void pmap_mark_clean(struct vas vas, vaddr_t va);
+
+/*
* Mark a virtual address with a specific
* caching type.
*/
diff --git a/sys/include/vm/vm_device.h b/sys/include/vm/vm_device.h
new file mode 100644
index 0000000..da476e2
--- /dev/null
+++ b/sys/include/vm/vm_device.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VM_DEVICE_H_
+#define _VM_DEVICE_H_
+
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/device.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_obj.h>
+
+extern const struct vm_pagerops vm_vnops;
+
+struct vm_object *dv_attach(devmajor_t major, dev_t dev, vm_prot_t prot);
+
+#endif /* !_VM_DEVICE_H_ */
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
+};
diff --git a/sys/vm/vm_device.c b/sys/vm/vm_device.c
new file mode 100644
index 0000000..e990b47
--- /dev/null
+++ b/sys/vm/vm_device.c
@@ -0,0 +1,78 @@
+/*
+ * 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/device.h>
+#include <sys/syslog.h>
+#include <vm/vm_device.h>
+
+#define pr_trace(fmt, ...) kprintf("vm_device: " fmt, ##__VA_ARGS__)
+#define pr_error(...) pr_trace(__VA_ARGS__)
+
+const struct vm_pagerops dv_vnops;
+
+/*
+ * Attach a cdev to a vm_object
+ *
+ * @major: Char device major
+ * @minor: Char device minor.
+ */
+struct vm_object *
+dv_attach(devmajor_t major, dev_t dev, vm_prot_t prot)
+{
+ int error;
+ struct cdevsw *cdevp;
+ struct vm_object *vmobj;
+
+ if ((cdevp = dev_get(major, dev)) == NULL) {
+ pr_error("bad attach (major=%d, dev=%d)\n", major, dev);
+ return NULL;
+ }
+
+ if (cdevp->mmap == NULL) {
+ pr_error("cdev lacks mmap() (major=%d, dev=%d)\n", major, dev);
+ return NULL;
+ }
+
+ error = vm_obj_init(&cdevp->vmobj, &dv_vnops, 1);
+ if (error != 0) {
+ return NULL;
+ }
+
+ vmobj = &cdevp->vmobj;
+ vmobj->prot = prot;
+ vmobj->data = cdevp;
+ vmobj->pgops = &dv_vnops;
+ return vmobj;
+}
+
+/* TODO */
+const struct vm_pagerops dv_vnops = {
+ .get = NULL,
+};
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index b56e896..b8f4aee 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -35,8 +35,10 @@
#include <sys/syscall.h>
#include <sys/syslog.h>
#include <sys/mman.h>
+#include <sys/filedesc.h>
#include <vm/dynalloc.h>
#include <vm/vm_pager.h>
+#include <vm/vm_device.h>
#include <vm/pmap.h>
#include <vm/map.h>
#include <vm/vm.h>
@@ -159,9 +161,12 @@ vm_map_modify(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot, bool unmap
void *
mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
{
- struct vm_object *map_obj;
+ struct vm_object *map_obj = NULL;
+ struct cdevsw *cdevp;
struct vm_page *pg;
struct mmap_entry *ep;
+ struct vnode *vp;
+ struct filedesc *fdp;
struct proc *td;
struct vas vas;
int error, npgs;
@@ -172,6 +177,7 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
misalign = len & (DEFAULT_PAGESIZE - 1);
len = ALIGN_UP(len + misalign, DEFAULT_PAGESIZE);
npgs = len / DEFAULT_PAGESIZE;
+ vas = pmap_read_vas();
if (addr == NULL) {
pr_error("mmap: NULL addr not supported\n");
@@ -179,25 +185,68 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
}
/* Validate flags */
- if (ISSET(flags, MAP_FIXED | MAP_SHARED)) {
- pr_error("mmap: fixed/shared mappings not yet supported\n");
+ if (ISSET(flags, MAP_FIXED)) {
+ pr_error("mmap: fixed mappings not yet supported\n");
mmap_dbg(addr, len, prot, flags, fildes, off);
return NULL;
}
- map_obj = dynalloc(sizeof(*map_obj));
- if (map_obj == NULL) {
- kprintf("mmap: failed to allocate map object\n");
- return NULL;
+
+ /*
+ * Attempt to open the file if mapping
+ * is shared.
+ */
+ if (ISSET(flags, MAP_SHARED)) {
+ fdp = fd_get(fildes);
+ if (fdp == NULL) {
+ pr_error("mmap: no such fd (fd=%d)\n", fildes);
+ return NULL;
+ }
+
+ vp = fdp->vp;
+ if (vp->type != VCHR) {
+ /* TODO */
+ pr_error("mmap: only device files supported\n");
+ return NULL;
+ }
+
+ map_obj = dv_attach(vp->major, vp->dev, prot);
+ if (map_obj == NULL) {
+ kprintf("mmap: dv_attach() failure\n");
+ return NULL;
+ }
+
+ cdevp = map_obj->data;
+ if ((pa = cdevp->mmap(vp->dev, off, 0)) == 0) {
+ kprintf("mmap: dev mmap() gave 0\n");
+ return NULL;
+ }
+
+ va = ALIGN_DOWN((vaddr_t)addr, DEFAULT_PAGESIZE);
+ error = vm_map(vas, va, pa, prot, len);
+ if (error != 0) {
+ kprintf("mmap: map failed (error=%d)\n", error);
+ return NULL;
+ }
+
+ goto done;
}
- error = vm_obj_init(map_obj, &vm_anonops, 1);
- if (error < 0) {
- kprintf("mmap: vm_obj_init() returned %d\n", error);
- kprintf("mmap: failed to init object\n");
- return NULL;
+
+ /* Only allocate new obj if needed */
+ if (map_obj == NULL) {
+ map_obj = dynalloc(sizeof(*map_obj));
+ if (map_obj == NULL) {
+ kprintf("mmap: failed to allocate map object\n");
+ return NULL;
+ }
+ error = vm_obj_init(map_obj, &vm_anonops, 1);
+ if (error < 0) {
+ kprintf("mmap: vm_obj_init() returned %d\n", error);
+ kprintf("mmap: failed to init object\n");
+ return NULL;
+ }
}
/* XXX: Assuming private */
- vas = pmap_read_vas();
va = ALIGN_DOWN((vaddr_t)addr, DEFAULT_PAGESIZE);
for (int i = 0; i < npgs; ++i) {
@@ -211,13 +260,13 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
pa = pg->phys_addr;
error = vm_map(vas, va, pa, prot, len);
- pr_trace("va=%p, len=%d\n", va, len);
if (error < 0) {
pr_error("mmap: failed to map page (retval=%x)\n", error);
return NULL;
}
}
+done:
/* Add entry to ledger */
td = this_td();
ep = dynalloc(sizeof(*ep));
diff --git a/sys/vm/vm_vnode.c b/sys/vm/vm_vnode.c
index 2457c97..27defc9 100644
--- a/sys/vm/vm_vnode.c
+++ b/sys/vm/vm_vnode.c
@@ -162,7 +162,6 @@ vn_attach(struct vnode *vp, vm_prot_t prot)
if (vp->type != VREG) {
pr_error("vn_attach: vp=%p, prot=%x\n", vp, prot);
- pr_error("vn_attach: Special files not supported yet!\n");
return NULL;
}