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/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/vector.S126
-rw-r--r--sys/arch/amd64/isa/spkr.c53
-rw-r--r--sys/dev/cons/cons.c27
-rw-r--r--sys/dev/cons/cons_ansi.c165
-rw-r--r--sys/dev/usb/xhci.c18
-rw-r--r--sys/dev/video/fbdev.c85
-rw-r--r--sys/fs/devfs.c2
-rw-r--r--sys/include/arch/amd64/cdefs.h9
-rw-r--r--sys/include/arch/amd64/cpu.h8
-rw-r--r--sys/include/dev/cons/ansi.h74
-rw-r--r--sys/include/dev/cons/cons.h4
-rw-r--r--sys/include/dev/video/fbdev.h1
-rw-r--r--sys/include/sys/device.h5
-rw-r--r--sys/include/sys/fbdev.h40
-rw-r--r--sys/include/sys/limits.h4
-rw-r--r--sys/include/sys/mman.h22
-rw-r--r--sys/include/sys/spawn.h3
-rw-r--r--sys/include/sys/syscall.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/kern_exit.c10
-rw-r--r--sys/kern/kern_spawn.c21
-rw-r--r--sys/kern/kern_stub.c12
-rw-r--r--sys/kern/kern_syscall.c3
-rw-r--r--sys/vm/vm_device.c78
-rw-r--r--sys/vm/vm_map.c124
-rw-r--r--sys/vm/vm_vnode.c1
33 files changed, 982 insertions, 116 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/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/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/isa/spkr.c b/sys/arch/amd64/isa/spkr.c
index b1bd2a2..b2f63b0 100644
--- a/sys/arch/amd64/isa/spkr.c
+++ b/sys/arch/amd64/isa/spkr.c
@@ -30,14 +30,60 @@
#include <sys/cdefs.h>
#include <sys/errno.h>
#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/driver.h>
+#include <fs/devfs.h>
#include <dev/timer.h>
#include <machine/isa/spkr.h>
#include <machine/isa/i8254.h>
#include <machine/pio.h>
+#include <string.h>
#define DIVIDEND 1193180
#define CTRL_PORT 0x61
+static struct cdevsw beep_cdevsw;
+
+/*
+ * Write to the pcspkr
+ *
+ * Bits 15:0 - frequency (hz)
+ * Bits 31:16 - duration (msec)
+ */
+static int
+dev_write(dev_t dev, struct sio_txn *sio, int flags)
+{
+ uint32_t payload = 0;
+ uint16_t hz;
+ uint16_t duration;
+ size_t len = sizeof(payload);
+
+ if (sio->len < len) {
+ return -EINVAL;
+ }
+
+ memcpy(&payload, sio->buf, len);
+ hz = payload & 0xFFFF;
+ duration = (payload >> 16) & 0xFFFF;
+ pcspkr_tone(hz, duration);
+ return sio->len;
+}
+
+static int
+beep_init(void)
+{
+ char devname[] = "beep";
+ devmajor_t major;
+ dev_t dev;
+
+ /* Register the device here */
+ major = dev_alloc_major();
+ dev = dev_alloc(major);
+ dev_register(major, dev, &beep_cdevsw);
+ devfs_create_entry(devname, major, dev, 0666);
+ return 0;
+}
+
int
pcspkr_tone(uint16_t freq, uint32_t msec)
{
@@ -67,3 +113,10 @@ pcspkr_tone(uint16_t freq, uint32_t msec)
outb(CTRL_PORT, tmp & ~3);
return 0;
}
+
+static struct cdevsw beep_cdevsw = {
+ .read = noread,
+ .write = dev_write
+};
+
+DRIVER_EXPORT(beep_init);
diff --git a/sys/dev/cons/cons.c b/sys/dev/cons/cons.c
index 61254a7..671d5f0 100644
--- a/sys/dev/cons/cons.c
+++ b/sys/dev/cons/cons.c
@@ -158,6 +158,8 @@ cons_handle_special(struct cons_screen *scr, char c)
}
switch (c) {
+ case ASCII_NUL:
+ return 0;
case ASCII_BS:
bp = scr->ob[scr->ch_row];
if (bp->head > bp->tail) {
@@ -262,6 +264,14 @@ cons_fast_putch(struct cons_screen *scr, char c)
{
struct cons_char cc;
struct cons_buf *bp;
+ int ansi;
+
+ ansi = ansi_feed(&scr->ansi_s, c);
+ if (ansi > 0) {
+ c = ASCII_NUL;
+ } else if (ansi < 0) {
+ c = ASCII_NUL;
+ }
/* Handle specials */
if (cons_handle_special(scr, c) == 0) {
@@ -379,6 +389,23 @@ cons_init_bufs(struct cons_screen *scr)
}
/*
+ * Reset console color.
+ */
+void
+cons_reset_color(struct cons_screen *scr)
+{
+ g_root_scr.fg = CONSOLE_FG;
+ g_root_scr.bg = CONSOLE_BG;
+}
+
+void
+cons_update_color(struct cons_screen *scr, uint32_t fg, uint32_t bg)
+{
+ scr->fg = fg;
+ scr->bg = bg;
+}
+
+/*
* Put a character on the screen.
*
* @scr: Screen.
diff --git a/sys/dev/cons/cons_ansi.c b/sys/dev/cons/cons_ansi.c
new file mode 100644
index 0000000..a91f1d3
--- /dev/null
+++ b/sys/dev/cons/cons_ansi.c
@@ -0,0 +1,165 @@
+/*
+ * 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/cdefs.h>
+#include <dev/cons/cons.h>
+#include <dev/cons/ansi.h>
+#include <string.h>
+
+__always_inline static inline bool
+is_valid_color(int c)
+{
+ return c >= '0' && c <= '7';
+}
+
+static inline void
+ansi_reset(struct ansi_state *statep)
+{
+ memset(statep, 0, sizeof(*statep));
+}
+
+/*
+ * Feed a byte into the ANSI escape sequence
+ * state machine.
+ *
+ * @statep: State machine pointer.
+ * @c: Byte to feed.
+ *
+ * On success, `c' is returned. On failure,
+ * 0 is returned. Values less than 0 indicate
+ * success with console attributes updated
+ * (ANSI_UPDATE_*).
+ */
+int
+ansi_feed(struct ansi_state *statep, char c)
+{
+ /* Standard colors */
+ static uint32_t colortab[] = {
+ ANSI_BLACK, ANSI_RED,
+ ANSI_GREEN, ANSI_YELLOW,
+ ANSI_BLUE, ANSI_MAGENTA,
+ ANSI_CYAN, ANSI_WHITE
+ };
+
+ /*
+ * Handle the control sequence introducer
+ * bytes.
+ */
+ switch (statep->csi) {
+ case 0: /* '\033' */
+ if (c != '\033') {
+ return 0;
+ }
+ statep->csi = 1;
+ statep->prev = c;
+ return c;
+ case 1: /* '[' */
+ if (c != '[') {
+ ansi_reset(statep);
+ return 0;
+ }
+ statep->csi = 2;
+ statep->prev = c;
+ return c;
+ }
+
+ if (!statep->set_fg && !statep->set_bg) {
+ /* Reset attributes? */
+ if (statep->reset_color) {
+ ansi_reset(statep);
+ cons_reset_color(&g_root_scr);
+ return ANSI_UPDATE_COLOR;
+ }
+
+ /* Mark attributes to be reset? */
+ if (c == '0') {
+ statep->reset_color = 1;
+ statep->prev = c;
+ return c;
+ }
+
+ /* Expect foreground */
+ if (c != '3') {
+ ansi_reset(statep);
+ return 0;
+ }
+ statep->set_fg = 1;
+ statep->prev = c;
+ return c;
+ }
+
+ if (statep->set_fg && c != ';') {
+ /* Make sure this is valid */
+ if (!is_valid_color(c)) {
+ ansi_reset(statep);
+ return 0;
+ }
+
+ /* Set the foreground */
+ statep->fg = colortab[c - '0'];
+ statep->set_bg = 1;
+ statep->set_fg = 0;
+ statep->prev = c;
+ return c;
+ }
+
+ if (statep->set_bg) {
+ if (c == ';') {
+ statep->prev = c;
+ return c;
+ }
+
+ /* Expect '4' after ';' */
+ if (statep->prev == ';' && c != '4') {
+ ansi_reset(statep);
+ return 0;
+ }
+
+ if (c == 'm') {
+ cons_update_color(&g_root_scr, statep->fg, statep->bg);
+ ansi_reset(statep);
+ return ANSI_UPDATE_COLOR;
+ }
+
+ /* Make sure this is valid */
+ if (!is_valid_color(c)) {
+ ansi_reset(statep);
+ return 0;
+ }
+
+ /* Set the background */
+ statep->bg = colortab[c - '0'];
+ statep->prev = c;
+ return c;
+ }
+
+ ansi_reset(statep);
+ return 0;
+}
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index 9ab109a..2b55f16 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>
@@ -175,6 +176,7 @@ xhci_init_scratchpads(struct xhci_hc *hc)
struct xhci_caps *caps = XHCI_CAPS(hc->base);
uint16_t max_bufs_lo, max_bufs_hi;
uint16_t max_bufs;
+ uint32_t npages;
uintptr_t *bufarr, tmp;
max_bufs_lo = XHCI_MAX_SP_LO(caps->hcsparams1);
@@ -188,8 +190,9 @@ xhci_init_scratchpads(struct xhci_hc *hc)
return 0;
}
- pr_trace("using %d pages for xHC scratchpads\n");
- bufarr = dynalloc_memalign(sizeof(uintptr_t)*max_bufs, 0x1000);
+ npages = (sizeof(uint64_t) * max_bufs) / DEFAULT_PAGESIZE;
+ pr_trace("using %d pages for xHC scratchpads\n", npages);
+ bufarr = dynalloc_memalign(npages * DEFAULT_PAGESIZE, 0x1000);
if (bufarr == NULL) {
pr_error("failed to allocate scratchpad buffer array\n");
return -1;
@@ -496,6 +499,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 +541,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..8a2499d 100644
--- a/sys/dev/video/fbdev.c
+++ b/sys/dev/video/fbdev.c
@@ -28,17 +28,65 @@
*/
#include <sys/types.h>
+#include <sys/errno.h>
#include <sys/limine.h>
+#include <sys/device.h>
+#include <sys/driver.h>
+#include <sys/fbdev.h>
#include <dev/video/fbdev.h>
+#include <fs/devfs.h>
+#include <fs/ctlfs.h>
+#include <vm/vm.h>
+#include <string.h>
#define FRAMEBUFFER \
framebuffer_req.response->framebuffers[0]
+static struct cdevsw fb_cdevsw;
+static const struct ctlops fb_size_ctl;
static volatile struct limine_framebuffer_request framebuffer_req = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 0
};
+static paddr_t
+fbdev_mmap(dev_t dev, size_t size, off_t off, int flags)
+{
+ size_t max_bounds;
+
+ max_bounds = FRAMEBUFFER->pitch * FRAMEBUFFER->height;
+ if ((off + size) > max_bounds) {
+ return 0;
+ }
+
+ return VIRT_TO_PHYS(FRAMEBUFFER->address);
+}
+
+static int
+ctl_attr_read(struct ctlfs_dev *cdp, struct sio_txn *sio)
+{
+ struct fbattr attr;
+ size_t len = sizeof(attr);
+
+ if (sio == NULL) {
+ return -EINVAL;
+ }
+ if (sio->buf == NULL) {
+ return -EINVAL;
+ }
+
+ if (len > sio->len) {
+ len = sio->len;
+ }
+
+ attr.width = FRAMEBUFFER->width;
+ attr.height = FRAMEBUFFER->height;
+ attr.pitch = FRAMEBUFFER->pitch;
+ attr.bpp = FRAMEBUFFER->bpp;
+ memcpy(sio->buf, &attr, len);
+ return len;
+}
+
struct fbdev
fbdev_get(void)
{
@@ -51,3 +99,40 @@ fbdev_get(void)
ret.bpp = FRAMEBUFFER->bpp;
return ret;
}
+
+static int
+fbdev_init(void)
+{
+ struct ctlfs_dev ctl;
+ 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);
+
+
+ /* Register control files */
+ ctl.mode = 0444;
+ ctlfs_create_node(devname, &ctl);
+ ctl.devname = devname;
+ ctl.ops = &fb_size_ctl;
+ ctlfs_create_entry("attr", &ctl);
+ return 0;
+}
+
+static struct cdevsw fb_cdevsw = {
+ .read = noread,
+ .write = nowrite,
+ .mmap = fbdev_mmap
+};
+
+static const struct ctlops fb_size_ctl = {
+ .read = ctl_attr_read,
+ .write = NULL,
+};
+
+DRIVER_EXPORT(fbdev_init);
diff --git a/sys/fs/devfs.c b/sys/fs/devfs.c
index a2ac7e8..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;
}
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/cons/ansi.h b/sys/include/dev/cons/ansi.h
new file mode 100644
index 0000000..98d7618
--- /dev/null
+++ b/sys/include/dev/cons/ansi.h
@@ -0,0 +1,74 @@
+/*
+ * 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 _CONS_ANSI_H_
+#define _CONS_ANSI_H_
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+/* ANSI colors */
+#define ANSI_BLACK 0x000000
+#define ANSI_RED 0xAA0000
+#define ANSI_GREEN 0x00AA00
+#define ANSI_BLUE 0x0000AA
+#define ANSI_YELLOW 0xAA5500
+#define ANSI_MAGENTA 0xAA00AA
+#define ANSI_CYAN 0x00AAAA
+#define ANSI_WHITE 0xAAAAAA
+
+/* ANSI_FEED update codes */
+#define ANSI_UPDATE_COLOR -1
+
+/*
+ * ANSI parser state machine.
+ *
+ * @prev: Previous char
+ * @csi: Encountered control seq introducer
+ * @reset_color: 1 if color is to be reset
+ * @set_fg: 1 if fg is being set
+ * @set_bg: 1 if bg is being set
+ * @fg: Foreground color
+ * @bg: Background color
+ * @flags: State flags
+ */
+struct ansi_state {
+ char prev;
+ uint8_t csi : 2;
+ uint8_t reset_color : 1;
+ uint8_t set_fg : 1;
+ uint8_t set_bg : 1;
+ uint32_t fg;
+ uint32_t bg;
+};
+
+int ansi_feed(struct ansi_state *statep, char c);
+
+#endif /* !_CONS_ANSI_H_ */
diff --git a/sys/include/dev/cons/cons.h b/sys/include/dev/cons/cons.h
index b27be23..13153b2 100644
--- a/sys/include/dev/cons/cons.h
+++ b/sys/include/dev/cons/cons.h
@@ -34,6 +34,7 @@
#include <sys/spinlock.h>
#include <dev/video/fbdev.h>
#include <dev/cons/consvar.h>
+#include <dev/cons/ansi.h>
struct cons_char {
char c;
@@ -45,6 +46,7 @@ struct cons_char {
struct cons_screen {
struct fbdev fbdev;
+ struct ansi_state ansi_s;
uint32_t fg;
uint32_t bg;
@@ -64,6 +66,8 @@ struct cons_screen {
void cons_init(void);
void cons_expose(void);
+void cons_update_color(struct cons_screen *scr, uint32_t fg, uint32_t bg);
+void cons_reset_color(struct cons_screen *scr);
int cons_putch(struct cons_screen *scr, char c);
int cons_putstr(struct cons_screen *scr, const char *s, size_t len);
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..04b66fc 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, size_t size, off_t off, int flags);
+
+ /* Private */
+ struct vm_object vmobj;
};
struct bdevsw {
diff --git a/sys/include/sys/fbdev.h b/sys/include/sys/fbdev.h
new file mode 100644
index 0000000..e206889
--- /dev/null
+++ b/sys/include/sys/fbdev.h
@@ -0,0 +1,40 @@
+/*
+ * 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 _SYS_FBDEV_H_
+#define _SYS_FBDEV_H_
+
+struct fbattr {
+ uint32_t width;
+ uint32_t height;
+ uint32_t pitch;
+ uint32_t bpp;
+};
+
+#endif /* !_SYS_FBDEV_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/mman.h b/sys/include/sys/mman.h
index 4ead9ba..08f506d 100644
--- a/sys/include/sys/mman.h
+++ b/sys/include/sys/mman.h
@@ -35,6 +35,8 @@
#if defined(_KERNEL)
#include <sys/tree.h>
#include <vm/vm_obj.h>
+#else
+#include <stddef.h>
#endif /* _KERNEL */
/*
@@ -80,19 +82,19 @@ struct mmap_lgdr {
size_t nbytes;
};
-/* Kernel munmap() routine */
-int munmap_at(void *addr, size_t len);
-
-/* Kernel mmap() routine */
-void *mmap_at(void *addr, size_t len, int prot, int flags,
- int fildes, off_t off);
-
int mmap_entrycmp(const struct mmap_entry *a, const struct mmap_entry *b);
RBT_PROTOTYPE(lgdr_entries, mmap_entry, hd, mmap_entrycmp)
-#endif /* _KERNEL */
/* Syscall layer */
-scret_t mmap(struct syscall_args *scargs);
-scret_t munmap(struct syscall_args *scargs);
+scret_t sys_mmap(struct syscall_args *scargs);
+scret_t sys_munmap(struct syscall_args *scargs);
+#endif /* _KERNEL */
+
+/* Kernel munmap() routine */
+int munmap(void *addr, size_t len);
+
+/* Kernel mmap() routine */
+void *mmap(void *addr, size_t len, int prot, int flags,
+ int fildes, off_t off);
#endif /* !_SYS_MMAN_H_ */
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/syscall.h b/sys/include/sys/syscall.h
index 2223a96..dad2e00 100644
--- a/sys/include/sys/syscall.h
+++ b/sys/include/sys/syscall.h
@@ -48,6 +48,8 @@
#define SYS_write 7
#define SYS_spawn 8
#define SYS_reboot 9
+#define SYS_mmap 10
+#define SYS_munmap 11
#if defined(_KERNEL)
/* Syscall return value and arg type */
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/kern_exit.c b/sys/kern/kern_exit.c
index a421e52..b6cbc4e 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -111,6 +111,7 @@ int
exit1(struct proc *td, int flags)
{
struct proc *curtd, *procp;
+ struct proc *parent;
struct cpu_info *ci;
pid_t target_pid, curpid;
@@ -120,6 +121,7 @@ exit1(struct proc *td, int flags)
curpid = curtd->pid;
td->flags |= PROC_EXITING;
+ parent = td->parent;
/* If we have any children, kill them too */
if (td->nleaves > 0) {
@@ -149,6 +151,13 @@ exit1(struct proc *td, int flags)
*/
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();
}
@@ -163,6 +172,7 @@ sys_exit(struct syscall_args *scargs)
{
struct proc *td = this_td();
+ td->data = scargs->tf;
td->exit_status = scargs->arg0;
exit1(td, 0);
__builtin_unreachable();
diff --git a/sys/kern/kern_spawn.c b/sys/kern/kern_spawn.c
index 3360443..4105668 100644
--- a/sys/kern/kern_spawn.c
+++ b/sys/kern/kern_spawn.c
@@ -111,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) {
@@ -161,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 fa1be65..17c6e54 100644
--- a/sys/kern/kern_stub.c
+++ b/sys/kern/kern_stub.c
@@ -40,7 +40,9 @@ sigfpe_default(int signo)
static struct proc *td;
td = this_td();
- kprintf("Floating point exception (pid=%d)\n", td->pid);
+ syslog_silence(false);
+ kprintf(OMIT_TIMESTAMP "Floating point exception (pid=%d)\n", td->pid);
+ syslog_silence(true);
exit1(td, 0);
}
@@ -50,7 +52,9 @@ sigkill_default(int signo)
static struct proc *td;
td = this_td();
- kprintf("Terminated (pid=%d)\n", td->pid);
+ syslog_silence(false);
+ kprintf(OMIT_TIMESTAMP "Terminated (pid=%d)\n", td->pid);
+ syslog_silence(true);
exit1(td, 0);
}
@@ -60,7 +64,9 @@ sigsegv_default(int signo)
static struct proc *td;
td = this_td();
- kprintf("Segmentation fault (pid=%d)\n", td->pid);
+ syslog_silence(false);
+ kprintf(OMIT_TIMESTAMP "Segmentation fault (pid=%d)\n", td->pid);
+ syslog_silence(true);
exit1(td, 0);
}
diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c
index 249a04a..8a66f0e 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -31,6 +31,7 @@
#include <sys/sysctl.h>
#include <sys/reboot.h>
#include <sys/types.h>
+#include <sys/mman.h>
#include <sys/proc.h>
#include <sys/vfs.h>
@@ -45,6 +46,8 @@ scret_t(*g_sctab[])(struct syscall_args *) = {
sys_write, /* SYS_write */
sys_spawn, /* SYS_spawn */
sys_reboot, /* SYS_reboot */
+ sys_mmap, /* SYS_mmap */
+ sys_munmap, /* SYS_munap */
};
const size_t MAX_SYSCALLS = NELEM(g_sctab);
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..26effdb 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>
@@ -157,51 +159,113 @@ vm_map_modify(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot, bool unmap
* crashes.
*/
void *
-mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
+mmap(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;
paddr_t pa;
vaddr_t va;
size_t misalign;
+ off_t page_off;
misalign = len & (DEFAULT_PAGESIZE - 1);
len = ALIGN_UP(len + misalign, DEFAULT_PAGESIZE);
npgs = len / DEFAULT_PAGESIZE;
-
- if (addr == NULL) {
- pr_error("mmap: NULL addr not supported\n");
- return NULL;
- }
+ vas = pmap_read_vas();
/* 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, len, off, 0)) == 0) {
+ kprintf("mmap: dev mmap() gave 0\n");
+ return NULL;
+ }
+
+ /*
+ * If the address passed is NULL, just identity
+ * map everything.
+ *
+ * XXX: This is why the bounds check done in the
+ * cdev mmap() *must* be correct.
+ *
+ * TODO: Use copy-on-write for this instead. Since mapping
+ * certain devices may required a lot of memory to
+ * be referenced anyways, we could use a buffered
+ * copy-on-write technique where only a window of
+ * pages can be mapped on-demand and other pages
+ * freed when that window is exceeded.
+ */
+ if (addr == NULL) {
+ addr = (void *)pa;
+ }
+
+ 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) {
pg = vm_pagealloc(map_obj, PALLOC_ZERO);
+ page_off = i * DEFAULT_PAGESIZE;
if (pg == NULL) {
/* TODO */
@@ -209,15 +273,21 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
return NULL;
}
+ /* TODO: copy-on-write */
+ if (addr == NULL) {
+ va = pg->phys_addr;
+ addr = (void *)va;
+ }
+
pa = pg->phys_addr;
- error = vm_map(vas, va, pa, prot, len);
- pr_trace("va=%p, len=%d\n", va, len);
+ error = vm_map(vas, va + page_off, pa, prot, 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));
@@ -243,7 +313,7 @@ mmap_at(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
* multiple of the machine page size.
*/
int
-munmap_at(void *addr, size_t len)
+munmap(void *addr, size_t len)
{
int pgno;
vaddr_t va;
@@ -299,7 +369,7 @@ munmap_at(void *addr, size_t len)
* arg5 -> off
*/
scret_t
-mmap(struct syscall_args *scargs)
+sys_mmap(struct syscall_args *scargs)
{
void *addr;
size_t len;
@@ -308,11 +378,11 @@ mmap(struct syscall_args *scargs)
addr = (void *)scargs->arg0;
len = scargs->arg1;
- prot = scargs->arg2;
+ prot = scargs->arg2 | PROT_USER;
flags = scargs->arg3;
fildes = scargs->arg4;
off = scargs->arg5;
- return (scret_t)mmap_at(addr, len, prot, flags, fildes, off);
+ return (scret_t)mmap(addr, len, prot, flags, fildes, off);
}
/*
@@ -322,14 +392,14 @@ mmap(struct syscall_args *scargs)
* arg1 -> len
*/
scret_t
-munmap(struct syscall_args *scargs)
+sys_munmap(struct syscall_args *scargs)
{
void *addr;
size_t len;
addr = (void *)scargs->arg0;
len = scargs->arg1;
- return (scret_t)munmap_at(addr, len);
+ return (scret_t)munmap(addr, len);
}
/*
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;
}