From 98ccb3a2d41015b42d46d8b382decc755a003c3f Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 4 Jun 2024 13:41:11 -0400
Subject: project: Initial commit

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/gdt.c     |  78 ++++++++++++++++++++++
 sys/arch/amd64/amd64/idt.c     |  70 ++++++++++++++++++++
 sys/arch/amd64/amd64/machdep.c |  69 ++++++++++++++++++++
 sys/arch/amd64/amd64/pio.c     |  74 +++++++++++++++++++++
 sys/arch/amd64/amd64/reboot.c  |  52 +++++++++++++++
 sys/arch/amd64/amd64/trap.S    | 143 +++++++++++++++++++++++++++++++++++++++++
 sys/arch/amd64/amd64/trap.c    |  38 +++++++++++
 sys/arch/amd64/conf/GENERIC    |   1 +
 sys/arch/amd64/conf/link.ld    |  47 ++++++++++++++
 9 files changed, 572 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/gdt.c
 create mode 100644 sys/arch/amd64/amd64/idt.c
 create mode 100644 sys/arch/amd64/amd64/machdep.c
 create mode 100644 sys/arch/amd64/amd64/pio.c
 create mode 100644 sys/arch/amd64/amd64/reboot.c
 create mode 100644 sys/arch/amd64/amd64/trap.S
 create mode 100644 sys/arch/amd64/amd64/trap.c
 create mode 100644 sys/arch/amd64/conf/GENERIC
 create mode 100644 sys/arch/amd64/conf/link.ld

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/gdt.c b/sys/arch/amd64/amd64/gdt.c
new file mode 100644
index 0000000..d9b7bf2
--- /dev/null
+++ b/sys/arch/amd64/amd64/gdt.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2023-2024 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 <machine/gdt.h>
+
+struct gdt_entry g_gdt_data[256] = {
+    /* Null */
+    {0},
+
+    /* Kernel code (0x8) */
+    {
+            .limit          = 0x0000,
+            .base_low       = 0x0000,
+            .base_mid       = 0x00,
+            .access         = 0x9A,
+            .granularity    = 0x20,
+            .base_hi        = 0x00
+    },
+
+    /* Kernel data (0x10) */
+    {
+            .limit          = 0x0000,
+            .base_low       = 0x0000,
+            .base_mid       = 0x00,
+            .access         = 0x92,
+            .granularity    = 0x00,
+            .base_hi        = 0x00
+    },
+
+    /* User code (0x18) */
+    {
+            .limit       = 0x0000,
+            .base_low    = 0x0000,
+            .base_mid    = 0x00,
+            .access      = 0xFA,
+            .granularity = 0xAF,
+            .base_hi     = 0x00
+    },
+
+    /* User data (0x20) */
+    {
+            .limit       = 0x0000,
+            .base_low    = 0x0000,
+            .base_mid    = 0x00,
+            .access      = 0xF2,
+            .granularity = 0x00,
+            .base_hi     = 0x00
+    },
+
+    /* TSS segment (0x28) */
+    {0}
+};
diff --git a/sys/arch/amd64/amd64/idt.c b/sys/arch/amd64/amd64/idt.c
new file mode 100644
index 0000000..a9507fc
--- /dev/null
+++ b/sys/arch/amd64/amd64/idt.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2023-2024 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 <machine/idt.h>
+#include <machine/gdt.h>
+
+#define LIDT(idtr) __ASMV("lidt %0" :: "m" (idtr))
+
+static struct idt_entry idt[256];
+static struct idtr idtr = {
+    .limit  = sizeof(struct idt_entry) * 256 - 1,
+    .offset = (uintptr_t)&idt[0]
+};
+
+void
+idt_set_desc(uint8_t vector, uint8_t type, uintptr_t isr, uint8_t ist)
+{
+    struct idt_entry *desc;
+
+    if (vector >= 255) {
+        /* Invalid vector */
+        return;
+    }
+
+    desc = &idt[vector];
+    desc->off_lo = isr & 0xFFFF;
+    desc->off_mid = (isr >> 16) & 0xFFFF;
+    desc->off_hi = (isr >> 32) & 0xFFFFFFFF;
+    desc->segsel = KERNEL_CS;
+    desc->type = type;
+    desc->dpl = (type == IDT_USER_INT_GATE) ? 3 : 0;
+    desc->p = 1;
+    desc->zero = 0;
+    desc->zero1 = 0;
+    desc->reserved = 0;
+    desc->ist = 0;
+}
+
+void
+idt_load(void)
+{
+    LIDT(idtr);
+}
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
new file mode 100644
index 0000000..19ba28a
--- /dev/null
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2023-2024 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 <machine/cpu.h>
+#include <machine/gdt.h>
+#include <machine/idt.h>
+#include <machine/trap.h>
+#include <machine/asm.h>
+#include <machine/cpuid.h>
+
+static struct cpu_info g_bsp_ci = {0};
+static struct gdtr bsp_gdtr = {
+    .limit = sizeof(struct gdt_entry) * 256 - 1,
+    .offset = (uintptr_t)&g_gdt_data[0]
+};
+
+static void
+setup_vectors(void)
+{
+    idt_set_desc(0x0, IDT_TRAP_GATE, ISR(arith_err), 0);
+    idt_set_desc(0x2, IDT_TRAP_GATE, ISR(nmi), 0);
+    idt_set_desc(0x3, IDT_TRAP_GATE, ISR(breakpoint_handler), 0);
+    idt_set_desc(0x4, IDT_TRAP_GATE, ISR(overflow), 0);
+    idt_set_desc(0x5, IDT_TRAP_GATE, ISR(bound_range), 0);
+    idt_set_desc(0x6, IDT_TRAP_GATE, ISR(invl_op), 0);
+    idt_set_desc(0x8, IDT_TRAP_GATE, ISR(double_fault), 0);
+    idt_set_desc(0xA, IDT_TRAP_GATE, ISR(invl_tss), 0);
+    idt_set_desc(0xB, IDT_TRAP_GATE, ISR(segnp), 0);
+    idt_set_desc(0xC, IDT_TRAP_GATE, ISR(ss_fault), 0);
+    idt_set_desc(0xD, IDT_TRAP_GATE, ISR(general_prot), 0);
+    idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0);
+}
+
+void
+cpu_startup(void)
+{
+    gdt_load(&bsp_gdtr);
+    idt_load();
+
+    setup_vectors();
+    amd64_write_gs_base((uintptr_t)&g_bsp_ci);
+}
diff --git a/sys/arch/amd64/amd64/pio.c b/sys/arch/amd64/amd64/pio.c
new file mode 100644
index 0000000..d4ce688
--- /dev/null
+++ b/sys/arch/amd64/amd64/pio.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2023-2024 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 <machine/pio.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+uint8_t
+inb(uint16_t port)
+{
+    uint8_t result;
+    __ASMV("in %%dx, %%al" : "=a" (result) : "d" (port));
+    return result;
+}
+
+uint16_t
+inw(uint16_t port)
+{
+    uint16_t val;
+    __ASMV("inw %w1, %w0" : "=a" (val) : "Nd" (port));
+    return val;
+}
+
+uint32_t
+inl(uint16_t port)
+{
+    uint32_t val;
+    __ASMV("inl %w1, %0" : "=a" (val) : "Nd" (port));
+    return val;
+}
+
+void
+outb(uint16_t port, uint8_t val)
+{
+    __ASMV("out %%al, %%dx" : :"a" (val), "d" (port));
+}
+
+void
+outw(uint16_t port, uint16_t val)
+{
+    __ASMV("outw %w0, %w1" : : "a" (val), "Nd" (port));
+}
+
+void
+outl(uint16_t port, uint32_t val)
+{
+    __ASMV("outl %0, %w1" : : "a" (val), "Nd" (port));
+}
diff --git a/sys/arch/amd64/amd64/reboot.c b/sys/arch/amd64/amd64/reboot.c
new file mode 100644
index 0000000..da1b46a
--- /dev/null
+++ b/sys/arch/amd64/amd64/reboot.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2023-2024 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/reboot.h>
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <machine/pio.h>
+
+__always_inline static inline void
+cpu_halt(void)
+{
+    __ASMV("cli; hlt");
+}
+
+void
+cpu_reboot(int method)
+{
+    if (ISSET(method, REBOOT_HALT)) {
+        cpu_halt();
+    }
+
+    /* Pulse the reset line until the machine goes down */
+    for (;;) {
+        outb(0x64, 0xFE);
+    }
+}
diff --git a/sys/arch/amd64/amd64/trap.S b/sys/arch/amd64/amd64/trap.S
new file mode 100644
index 0000000..fb3ca77
--- /dev/null
+++ b/sys/arch/amd64/amd64/trap.S
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2023-2024 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 <machine/frameasm.h>
+#include <machine/trap.h>
+
+.macro handle_trap
+    mov %rsp, %rdi
+    call trap_handler
+.endm
+
+    .text
+    .globl breakpoint_handler
+breakpoint_handler:
+    push_trapframe_ec $TRAP_BREAKPOINT
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl arith_err
+arith_err:
+    push_trapframe_ec $TRAP_ARITH_ERR
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl overflow
+overflow:
+    push_trapframe_ec $TRAP_OVERFLOW
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl bound_range
+bound_range:
+    push_trapframe_ec $TRAP_BOUND_RANGE
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl invl_op
+invl_op:
+    push_trapframe_ec $TRAP_INVLOP
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl double_fault
+double_fault:
+    push_trapframe_ec $TRAP_DOUBLE_FAULT
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl invl_tss
+invl_tss:
+    push_trapframe_ec $TRAP_INVLTSS
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl segnp
+segnp:
+    push_trapframe_ec $TRAP_SEGNP
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl general_prot
+general_prot:
+    push_trapframe_ec $TRAP_PROTFLT
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl page_fault
+page_fault:
+    push_trapframe_ec $TRAP_PAGEFLT
+
+    handle_trap
+    cli
+    hlt
+
+    .globl nmi
+nmi:
+    push_trapframe_ec $TRAP_NMI
+
+    handle_trap
+
+    cli
+    hlt
+
+    .globl ss_fault
+ss_fault:
+    push_trapframe_ec $TRAP_SS
+
+    handle_trap
+    cli
+    hlt
diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c
new file mode 100644
index 0000000..dcae075
--- /dev/null
+++ b/sys/arch/amd64/amd64/trap.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023-2024 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/reboot.h>
+#include <machine/trap.h>
+#include <machine/frame.h>
+
+void
+trap_handler(struct trapframe *tf)
+{
+    cpu_reboot(REBOOT_HALT);
+}
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
new file mode 100644
index 0000000..70b786d
--- /dev/null
+++ b/sys/arch/amd64/conf/GENERIC
@@ -0,0 +1 @@
+// TODO
diff --git a/sys/arch/amd64/conf/link.ld b/sys/arch/amd64/conf/link.ld
new file mode 100644
index 0000000..b073054
--- /dev/null
+++ b/sys/arch/amd64/conf/link.ld
@@ -0,0 +1,47 @@
+OUTPUT_FORMAT(elf64-x86-64)
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(main)
+
+PHDRS
+{
+    text          PT_LOAD    FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
+    rodata        PT_LOAD    FLAGS((1 << 2)) ;            /* Read only */
+    data          PT_LOAD    FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
+}
+
+SECTIONS
+{
+    . = 0xFFFFFFFF80000000;
+
+    .text : {
+        *(.text .text.*)
+    } :text
+
+    . += CONSTANT(MAXPAGESIZE);
+
+    .rodata : {
+        *(.rodata .rodata.*)
+    } :rodata
+
+    .drivers : {
+        __drivers_init_start = .;
+        *(.drivers .drivers)
+        __drivers_init_end = .;
+    } :rodata
+
+    . += CONSTANT(MAXPAGESIZE);
+
+    .data : {
+        *(.data .data.*)
+    } :data
+
+    .bss : {
+        *(COMMON)
+        *(.bss .bss.*)
+    } :data
+
+    /DISCARD/ : {
+        *(.eh_frame)
+        *(.note .note.*)
+    }
+}
-- 
cgit v1.2.3


From 7c29fb70b00315bba95fa2a8b044e88a8d0b32d1 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 4 Jun 2024 15:52:13 -0400
Subject: kernel/amd64: Add HPET driver

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/hpet.c   | 186 ++++++++++++++++++++++++++++++++++++++++++
 sys/dev/acpi/acpi_init.c      |  11 +++
 sys/include/arch/amd64/hpet.h |  37 +++++++++
 3 files changed, 234 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/hpet.c
 create mode 100644 sys/include/arch/amd64/hpet.h

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c
new file mode 100644
index 0000000..860e610
--- /dev/null
+++ b/sys/arch/amd64/amd64/hpet.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2023-2024 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/mmio.h>
+#include <sys/syslog.h>
+#include <machine/hpet.h>
+#include <dev/acpi/acpi.h>
+#include <dev/acpi/tables.h>
+#include <dev/timer.h>
+
+#define pr_trace(fmt, ...) kprintf("hpet: " fmt, ##__VA_ARGS__)
+#define pr_error(fmt, ...) pr_trace(__VA_ARGS__)
+
+#define HPET_REG_CAPS               0x00
+#define HPET_GENERAL_CONFIG         0x10
+#define HPET_REG_MAIN_COUNTER       0xF0
+
+#define CAP_REV_ID(caps)            (caps & 0xFF)
+#define CAP_NUM_TIM(caps)           (caps >> 8) & 0x1F
+#define CAP_CLK_PERIOD(caps)        (caps >> 32)
+
+#define FSEC_PER_SECOND 1000000000000000ULL
+#define USEC_PER_SECOND 1000000ULL
+
+static void *hpet_base = NULL;
+static struct timer timer = {0};
+
+/*
+ * Read from HPET register space.
+ *
+ * @reg: Register to read from.
+ */
+static inline uint64_t
+hpet_read(uint32_t reg)
+{
+    void *addr;
+
+    addr = (void *)((uintptr_t)hpet_base + reg);
+    return mmio_read64(addr);
+}
+
+/*
+ * Write to HPET register space.
+ *
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+static inline void
+hpet_write(uint32_t reg, uint64_t val)
+{
+    void *addr;
+
+    addr = (void *)((uintptr_t)hpet_base + reg);
+    mmio_write64(addr, val);
+}
+
+static int
+hpet_sleep(uint64_t n, uint64_t units)
+{
+    uint64_t caps;
+    uint32_t period;
+    uint64_t counter_val;
+    volatile size_t ticks;
+
+    caps = hpet_read(HPET_REG_CAPS);
+    period = CAP_CLK_PERIOD(caps);
+    counter_val = hpet_read(HPET_REG_MAIN_COUNTER);
+
+    ticks = counter_val + (n * (units / period));
+
+    while (hpet_read(HPET_REG_MAIN_COUNTER) < ticks) {
+        __ASMV("rep; nop");
+    }
+
+    return 0;
+}
+
+static int
+hpet_msleep(size_t ms)
+{
+    return hpet_sleep(ms, 1000000000000);
+}
+
+static int
+hpet_usleep(size_t us)
+{
+    return hpet_sleep(us, 1000000000);
+}
+
+static int
+hpet_nsleep(size_t ns)
+{
+    return hpet_sleep(ns, 1000000);
+}
+
+static size_t
+hpet_time_usec(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 * USEC_PER_SECOND) / freq;
+}
+
+static size_t
+hpet_time_sec(void)
+{
+    return hpet_time_usec() / USEC_PER_SECOND;
+}
+
+int
+hpet_init(void)
+{
+    struct acpi_gas *gas;
+    struct acpi_hpet *hpet;
+    uint64_t caps;
+
+    hpet = acpi_query("HPET");
+    if (hpet == NULL)
+        return -1;
+
+    gas = &hpet->gas;
+    hpet_base = (void *)gas->address;
+
+    /* Ensure caps aren't bogus */
+    caps = hpet_read(HPET_REG_CAPS);
+    if (CAP_REV_ID(caps) == 0) {
+        pr_error("Found bogus revision, assuming faulty\n");
+        return -1;
+    }
+    if (CAP_CLK_PERIOD(caps) > 0x05F5E100) {
+        /*
+         * The spec states this counter clk period must
+         * be <= 0x05F5E100. So we'll consider it as bogus
+         * if it exceeds this value
+         */
+        pr_error("Found bogus COUNTER_CLK_PERIOD, assuming faulty\n");
+        return 1;
+    }
+
+    pr_trace("HPET integrity verified\n");
+    hpet_write(HPET_REG_MAIN_COUNTER, 0);
+    hpet_write(HPET_GENERAL_CONFIG, 1);
+
+    /* Setup timer descriptor */
+    timer.name = "HIGH_PRECISION_EVENT_TIMER";
+    timer.msleep = hpet_msleep;
+    timer.usleep = hpet_usleep;
+    timer.nsleep = hpet_nsleep;
+    timer.get_time_usec = hpet_time_usec;
+    timer.get_time_sec = hpet_time_sec;
+    register_timer(TIMER_GP, &timer);
+    return 0;
+}
diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c
index a8423e4..f445d95 100644
--- a/sys/dev/acpi/acpi_init.c
+++ b/sys/dev/acpi/acpi_init.c
@@ -48,6 +48,16 @@ static volatile struct limine_rsdp_request rsdp_req = {
     .revision = 0
 };
 
+static void
+acpi_init_hpet(void)
+{
+#if defined(__x86_64__)
+    if (hpet_init() != 0) {
+        panic("Could not init HPET\n");
+    }
+#endif
+}
+
 /*
  * Writes out OEMID of ACPI header.
  *
@@ -107,4 +117,5 @@ acpi_init(void)
     }
 
     root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4;
+    acpi_init_hpet();
 }
diff --git a/sys/include/arch/amd64/hpet.h b/sys/include/arch/amd64/hpet.h
new file mode 100644
index 0000000..0ebc96b
--- /dev/null
+++ b/sys/include/arch/amd64/hpet.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_HPET_H_
+#define _MACHINE_HPET_H_
+
+#include <sys/types.h>
+
+int hpet_init(void);
+
+#endif  /* !_MACHINE_HPET_H_ */
-- 
cgit v1.2.3


From 31e9919ced2c577e601d17ec02a3d7886f793469 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 4 Jun 2024 20:43:41 -0400
Subject: kernel/amd64: trap: Add logging for debugging

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/trap.c | 59 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c
index dcae075..2d479ee 100644
--- a/sys/arch/amd64/amd64/trap.c
+++ b/sys/arch/amd64/amd64/trap.c
@@ -27,12 +27,69 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/param.h>
+#include <sys/cdefs.h>
 #include <sys/reboot.h>
+#include <sys/panic.h>
+#include <sys/syslog.h>
 #include <machine/trap.h>
 #include <machine/frame.h>
 
+#define pr_error(fmt, ...) kprintf("trap: " fmt, ##__VA_ARGS__)
+
+static const char *trap_type[] = {
+    [TRAP_BREAKPOINT]   = "breakpoint",
+    [TRAP_ARITH_ERR]    = "arithmetic error",
+    [TRAP_OVERFLOW]     = "overflow",
+    [TRAP_BOUND_RANGE]  = "bound range exceeded",
+    [TRAP_INVLOP]       = "invalid opcode",
+    [TRAP_DOUBLE_FAULT] = "double fault",
+    [TRAP_INVLTSS]      = "invalid TSS",
+    [TRAP_SEGNP]        = "segment not present",
+    [TRAP_PROTFLT]      = "general protection",
+    [TRAP_PAGEFLT]      = "page fault",
+    [TRAP_NMI]          = "non-maskable interrupt",
+    [TRAP_SS]           = "stack-segment fault"
+};
+
+static inline uintptr_t
+pf_faultaddr(void)
+{
+    uintptr_t cr2;
+    __ASMV("mov %%cr2, %0\n" : "=r" (cr2) :: "memory");
+    return cr2;
+}
+
+static void
+regdump(struct trapframe *tf)
+{
+    uintptr_t cr3, cr2 = pf_faultaddr();
+
+    __ASMV("mov %%cr3, %0\n"
+           : "=r" (cr3)
+           :
+           : "memory"
+    );
+
+    kprintf(OMIT_TIMESTAMP
+        "RAX=%p RCX=%p RDX=%p\n"
+        "RBX=%p RSI=%p RDI=%p\n"
+        "RFL=%p CR2=%p CR3=%p\n"
+        "RBP=%p RSP=%p RIP=%p\n",
+        tf->rax, tf->rcx, tf->rdx,
+        tf->rbx, tf->rsi, tf->rdi,
+        tf->rflags, cr2, cr3,
+        tf->rbp, tf->rsp, tf->rip);
+}
+
 void
 trap_handler(struct trapframe *tf)
 {
-    cpu_reboot(REBOOT_HALT);
+    if (tf->trapno >= NELEM(trap_type)) {
+        panic("Got unknown trap %d\n", tf->trapno);
+    }
+
+    pr_error("Got %s\n", trap_type[tf->trapno]);
+    regdump(tf);
+    panic("Fatal trap - halting\n");
 }
-- 
cgit v1.2.3


From 955d6a381f53c234ce1f4d52aa57f183ed9a6e65 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 4 Jun 2024 22:13:30 -0400
Subject: kernel/amd64: Support IBRS

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/machdep.c | 19 +++++++++++++++
 sys/arch/amd64/amd64/spectre.S | 53 ++++++++++++++++++++++++++++++++++++++++++
 sys/arch/amd64/conf/GENERIC    |  3 ++-
 sys/include/arch/amd64/msr.h   |  2 ++
 4 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100644 sys/arch/amd64/amd64/spectre.S

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 19ba28a..275c23e 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -35,6 +35,14 @@
 #include <machine/asm.h>
 #include <machine/cpuid.h>
 
+#if defined(__SPECTRE_IBRS)
+#define SPECTRE_IBRS  __SPECTRE_IBRS
+#else
+#define SPECTRE_IBRS 0
+#endif
+
+int ibrs_enable(void);
+
 static struct cpu_info g_bsp_ci = {0};
 static struct gdtr bsp_gdtr = {
     .limit = sizeof(struct gdt_entry) * 256 - 1,
@@ -58,6 +66,16 @@ setup_vectors(void)
     idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0);
 }
 
+static void
+try_mitigate_spectre(void)
+{
+    if (!SPECTRE_IBRS) {
+        return;
+    }
+
+    ibrs_enable();
+}
+
 void
 cpu_startup(void)
 {
@@ -66,4 +84,5 @@ cpu_startup(void)
 
     setup_vectors();
     amd64_write_gs_base((uintptr_t)&g_bsp_ci);
+    try_mitigate_spectre();
 }
diff --git a/sys/arch/amd64/amd64/spectre.S b/sys/arch/amd64/amd64/spectre.S
new file mode 100644
index 0000000..6781cbd
--- /dev/null
+++ b/sys/arch/amd64/amd64/spectre.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2023-2024 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 <machine/msr.h>
+
+    .text
+    .globl ibrs_enable
+    .type ibrs_enable, @function
+ibrs_enable:
+    /* See if it is supported */
+    mov $7, %eax
+    xor %ecx, %ecx
+    cpuid
+    bt $26, %edx
+    jnc fail
+
+    /* Now we enable it */
+    mov $IA32_SPEC_CTL, %ecx
+    rdmsr
+    or $1, %eax
+    wrmsr
+    xor %rax, %rax
+    jmp 1f
+fail:
+    mov $1, %rax
+1:
+    retq
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 70b786d..1a48a94 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1 +1,2 @@
-// TODO
+// Kernel options
+option SPECTRE_IBRS yes
diff --git a/sys/include/arch/amd64/msr.h b/sys/include/arch/amd64/msr.h
index bc0dbcb..6ad95f1 100644
--- a/sys/include/arch/amd64/msr.h
+++ b/sys/include/arch/amd64/msr.h
@@ -33,6 +33,7 @@
 #define IA32_SPEC_CTL       0x00000048
 #define IA32_KERNEL_GS_BASE 0xC0000102
 
+#if !defined(__ASSEMBLER__)
 static inline uint64_t
 rdmsr(uint32_t msr_addr)
 {
@@ -60,4 +61,5 @@ wrmsr(uint32_t msr_addr, uint64_t value)
     );
 }
 
+#endif  /* !__ASSEMBLER__ */
 #endif  /* !_MACHINE_MSR_H_ */
-- 
cgit v1.2.3


From efb3cd0e2ad09f409d66534d44ff07a55e9f1171 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 4 Jun 2024 22:17:28 -0400
Subject: kernel/amd64: acpi: Support parsing MADT

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/acpi_machdep.c | 74 +++++++++++++++++++++++++++++++++++++
 sys/dev/acpi/acpi_init.c            |  1 +
 sys/include/dev/acpi/acpivar.h      |  2 +
 sys/include/dev/acpi/tables.h       |  5 +++
 4 files changed, 82 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/acpi_machdep.c

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c
new file mode 100644
index 0000000..5f3b3bf
--- /dev/null
+++ b/sys/arch/amd64/amd64/acpi_machdep.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2023-2024 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/panic.h>
+#include <sys/syslog.h>
+#include <dev/acpi/acpi.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/tables.h>
+
+#define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__)
+
+int
+acpi_init_madt(void)
+{
+    struct acpi_madt *madt = acpi_query("APIC");
+    struct apic_header *apichdr;
+    struct ioapic *ioapic = NULL;
+    uint8_t *cur, *end;
+
+    if (madt == NULL) {
+        panic("Could not find MADT!\n");
+    }
+
+    cur = (uint8_t *)(madt + 1);
+    end = (uint8_t *)madt + madt->hdr.length;
+
+    while (cur < end) {
+        apichdr = (void *)cur;
+        if (apichdr->type == APIC_TYPE_IO_APIC) {
+            /*
+             * TODO: Figure out how to use multiple I/O APICs
+             */
+            if (ioapic != NULL) {
+                pr_trace("Skipping I/O APIC with ID %d\n", ioapic->ioapic_id);
+                break;
+            }
+
+            ioapic = (struct ioapic *)cur;
+            pr_trace("Detected I/O APIC (id=%d, gsi_base=%d)\n",
+                ioapic->ioapic_id, ioapic->gsi_base);
+        }
+
+        cur += apichdr->length;
+    }
+
+    return 0;
+
+}
diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c
index f445d95..4c0ae1b 100644
--- a/sys/dev/acpi/acpi_init.c
+++ b/sys/dev/acpi/acpi_init.c
@@ -118,4 +118,5 @@ acpi_init(void)
 
     root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4;
     acpi_init_hpet();
+    acpi_init_madt();
 }
diff --git a/sys/include/dev/acpi/acpivar.h b/sys/include/dev/acpi/acpivar.h
index 9a37dfb..9cfe945 100644
--- a/sys/include/dev/acpi/acpivar.h
+++ b/sys/include/dev/acpi/acpivar.h
@@ -35,6 +35,8 @@
 
 uint8_t acpi_checksum(struct acpi_header *hdr);
 struct acpi_root_sdt *acpi_get_root_sdt(void);
+
 size_t acpi_get_root_sdt_len(void);
+int acpi_init_madt(void);
 
 #endif  /* !_ACPI_ACPIVAR_H_ */
diff --git a/sys/include/dev/acpi/tables.h b/sys/include/dev/acpi/tables.h
index d5bfd52..1dca890 100644
--- a/sys/include/dev/acpi/tables.h
+++ b/sys/include/dev/acpi/tables.h
@@ -33,6 +33,11 @@
 #include <sys/types.h>
 #include <sys/cdefs.h>
 
+/* MADT APIC header types */
+#define APIC_TYPE_LOCAL_APIC            0
+#define APIC_TYPE_IO_APIC               1
+#define APIC_TYPE_INTERRUPT_OVERRIDE    2
+
 #define OEMID_SIZE 6
 
 struct __packed acpi_header {
-- 
cgit v1.2.3


From b7b304843f34b9f7d9c36d0603874f5050f5d83a Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 4 Jun 2024 22:18:32 -0400
Subject: kernel/amd64: Add I/O APIC driver

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/acpi_machdep.c |   3 +
 sys/arch/amd64/amd64/ioapic.c       | 230 ++++++++++++++++++++++++++++++++++++
 sys/include/arch/amd64/ioapic.h     |  44 +++++++
 sys/include/arch/amd64/ioapicvar.h  |  28 +++++
 4 files changed, 305 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/ioapic.c
 create mode 100644 sys/include/arch/amd64/ioapic.h
 create mode 100644 sys/include/arch/amd64/ioapicvar.h

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c
index 5f3b3bf..d1686df 100644
--- a/sys/arch/amd64/amd64/acpi_machdep.c
+++ b/sys/arch/amd64/amd64/acpi_machdep.c
@@ -32,6 +32,7 @@
 #include <dev/acpi/acpi.h>
 #include <dev/acpi/acpivar.h>
 #include <dev/acpi/tables.h>
+#include <machine/ioapic.h>
 
 #define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__)
 
@@ -64,6 +65,8 @@ acpi_init_madt(void)
             ioapic = (struct ioapic *)cur;
             pr_trace("Detected I/O APIC (id=%d, gsi_base=%d)\n",
                 ioapic->ioapic_id, ioapic->gsi_base);
+
+            ioapic_init((void *)(uintptr_t)ioapic->ioapic_addr);
         }
 
         cur += apichdr->length;
diff --git a/sys/arch/amd64/amd64/ioapic.c b/sys/arch/amd64/amd64/ioapic.c
new file mode 100644
index 0000000..39bf8f8
--- /dev/null
+++ b/sys/arch/amd64/amd64/ioapic.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2023-2024 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/syslog.h>
+#include <sys/panic.h>
+#include <sys/mmio.h>
+#include <machine/ioapicvar.h>
+#include <machine/ioapic.h>
+#include <dev/acpi/tables.h>
+#include <dev/acpi/acpi.h>
+
+#define pr_trace(fmt, ...) kprintf("ioapic: " fmt, ##__VA_ARGS__)
+#define IOAPIC_BASE_OFF(off) ((void *)((uintptr_t)ioapic_base + off))
+
+static void *ioapic_base = NULL;
+static struct acpi_madt *madt = NULL;
+
+/*
+ * Converts IRQ numbers to its corresponding
+ * Global System Interrupt (GSI) number.
+ *
+ * @irq: IRQ number.
+ */
+static uint32_t
+irq_to_gsi(uint8_t irq)
+{
+    struct apic_header *hdr = NULL;
+    struct interrupt_override *override = NULL;
+    uint8_t *cur = NULL;
+    uint8_t *end = NULL;
+
+    if (madt == NULL)
+        madt = acpi_query("APIC");
+    if (madt == NULL)
+        panic("Failed to fetch MADT\n");
+
+    cur = (uint8_t *)(madt + 1);
+    end = (uint8_t *)madt + madt->hdr.length;
+
+    while (cur < end) {
+        hdr = (void *)cur;
+
+        if (hdr->type == APIC_TYPE_INTERRUPT_OVERRIDE) {
+            override = (struct interrupt_override *)cur;
+            if (override->source == irq) {
+                return override->interrupt;
+            }
+        }
+
+        cur += hdr->length;
+    }
+
+    return irq;
+}
+
+/*
+ * Reads a 32 bit value from the IOAPIC
+ * register space.
+ *
+ * @reg: Register to read from.
+ */
+static uint32_t
+ioapic_readl(uint16_t reg)
+{
+    mmio_write32(IOAPIC_BASE_OFF(IOREGSEL), reg);
+    return mmio_read32(IOAPIC_BASE_OFF(IOWIN));
+}
+
+/*
+ * Writes a 32 bit value to the IOAPIC
+ * register space.
+ *
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+static void
+ioapic_writel(uint16_t reg, uint32_t val)
+{
+    mmio_write32(IOAPIC_BASE_OFF(IOREGSEL), reg);
+    mmio_write32(IOAPIC_BASE_OFF(IOWIN), val);
+}
+
+/*
+ * Reads an I/O APIC redirection entry.
+ *
+ * @entry: Entry variable to read into.
+ * @index: Index to read.
+ */
+static void
+ioapic_read_redentry(union ioapic_redentry *entry, uint8_t index)
+{
+    uint32_t lo, hi;
+
+    lo = ioapic_readl(IOREDTBL + index * 2);
+    hi = ioapic_readl(IOREDTBL + index * 2 + 1);
+    entry->value = ((uint64_t)hi << 32) | lo;
+}
+
+/*
+ * Writes an I/O APIC redirection entry.
+ *
+ * @entry: Entry variable to write.
+ * @index: Index to write to.
+ */
+static void
+ioapic_write_redentry(const union ioapic_redentry *entry, uint8_t index)
+{
+    ioapic_writel(IOREDTBL + index * 2, (uint32_t)entry->value);
+    ioapic_writel(IOREDTBL + index * 2 + 1, (uint32_t)(entry->value >> 32));
+}
+
+/*
+ * Mask I/O APIC pin with "raw" pin number
+ * (Global System Interrupt)
+ *
+ * @gsi: Global System Interrupt number
+ */
+void
+ioapic_gsi_mask(uint8_t gsi)
+{
+    union ioapic_redentry redentry;
+
+    ioapic_read_redentry(&redentry, gsi);
+    redentry.interrupt_mask = 1;
+    ioapic_write_redentry(&redentry, gsi);
+}
+
+/*
+ * Unmask I/O APIC pin with "raw" pin number
+ * (Global System Interrupt)
+ *
+ * @gsi: Global System Interrupt number
+ */
+void
+ioapic_gsi_unmask(uint8_t gsi)
+{
+    union ioapic_redentry redentry;
+
+    ioapic_read_redentry(&redentry, gsi);
+    redentry.interrupt_mask = 0;
+    ioapic_write_redentry(&redentry, gsi);
+}
+
+/*
+ * Masks I/O APIC pin via IRQ number
+ *
+ * @irq: Interrupt Request number
+ */
+void
+ioapic_irq_mask(uint8_t irq)
+{
+    uint8_t gsi = irq_to_gsi(irq);
+    ioapic_gsi_mask(gsi);
+}
+
+/*
+ * Unmasks I/O APIC pin via IRQ number
+ *
+ * @irq: Interrupt Request number
+ */
+void
+ioapic_irq_unmask(uint8_t irq)
+{
+    uint8_t gsi = irq_to_gsi(irq);
+    ioapic_gsi_unmask(gsi);
+}
+
+/*
+ * Assign an interrupt vector to a redirection
+ * entry.
+ *
+ * @irq: IRQ number to assign vector to.
+ * @vector: Vector assign.
+ */
+void
+ioapic_set_vec(uint8_t irq, uint8_t vector)
+{
+    union ioapic_redentry redentry;
+    uint8_t gsi = irq_to_gsi(irq);
+
+    ioapic_read_redentry(&redentry, gsi);
+    redentry.vector = vector;
+    ioapic_write_redentry(&redentry, gsi);
+}
+
+void
+ioapic_init(void *base)
+{
+    size_t tmp;
+    uint8_t redir_ent_cnt, ver;
+
+    ioapic_base = base;
+    tmp = ioapic_readl(IOAPICVER);
+    ver = tmp & 0xFF;
+    redir_ent_cnt = ((tmp >> 16) & 0xFF) + 1;
+
+    pr_trace("version=%d, address=0x%x\n", ver, base);
+    pr_trace("Masking %d GSIs...\n", redir_ent_cnt);
+
+    for (uint8_t i = 0; i < redir_ent_cnt; ++i) {
+        ioapic_gsi_mask(i);
+    }
+}
diff --git a/sys/include/arch/amd64/ioapic.h b/sys/include/arch/amd64/ioapic.h
new file mode 100644
index 0000000..4a0479f
--- /dev/null
+++ b/sys/include/arch/amd64/ioapic.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_IOAPIC_H_
+#define _MACHINE_IOAPIC_H_
+
+#include <sys/types.h>
+
+void ioapic_init(void *base);
+void ioapic_gsi_mask(uint8_t gsi);
+
+void ioapic_gsi_unmask(uint8_t gsi);
+void ioapic_irq_mask(uint8_t irq);
+
+void ioapic_irq_unmask(uint8_t irq);
+void ioapic_set_vec(uint8_t irq, uint8_t vector);
+
+#endif  /* !_MACHINE_IOAPIC_H_ */
diff --git a/sys/include/arch/amd64/ioapicvar.h b/sys/include/arch/amd64/ioapicvar.h
new file mode 100644
index 0000000..d5a75df
--- /dev/null
+++ b/sys/include/arch/amd64/ioapicvar.h
@@ -0,0 +1,28 @@
+#ifndef _MACHINE_IOAPICVAR_H_
+#define _MACHINE_IOAPICVAR_H_
+
+#include <sys/types.h>
+
+/* Register offsets */
+#define IOREGSEL    0x00
+#define IOWIN       0x10
+#define IOAPICVER   0x01
+#define IOREDTBL    0x10
+
+union ioapic_redentry {
+    struct {
+        uint8_t vector;
+        uint8_t delmod          : 3;
+        uint8_t destmod         : 1;
+        uint8_t delivs          : 1;
+        uint8_t intpol          : 1;
+        uint8_t remote_irr      : 1;
+        uint8_t trigger_mode    : 1;
+        uint8_t interrupt_mask  : 1;
+        uint64_t reserved       : 39;
+        uint8_t dest_field;
+    };
+    uint64_t value;
+};
+
+#endif  /* !_MACHINE_IOAPICVAR_H_ */
-- 
cgit v1.2.3


From 433d6e282c9f1455fef07333807424f4bd07878e Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Tue, 4 Jun 2024 23:28:15 -0400
Subject: kernel/amd64: spectre: Disable IBRS by default

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/conf/GENERIC | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 1a48a94..ea6ba76 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,2 +1,2 @@
 // Kernel options
-option SPECTRE_IBRS yes
+option SPECTRE_IBRS no
-- 
cgit v1.2.3


From dbfcd0e88e471564392549652d0bde2a967c34f4 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Wed, 5 Jun 2024 20:58:51 -0400
Subject: kernel/amd64: Add initial LAPIC code

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/acpi_machdep.c |   2 +
 sys/arch/amd64/amd64/lapic.c        | 214 ++++++++++++++++++++++++++++++++++++
 sys/arch/amd64/amd64/machdep.c      |  13 +++
 sys/include/arch/amd64/cpu.h        |   3 +-
 sys/include/arch/amd64/lapic.h      |  39 +++++++
 sys/include/arch/amd64/lapicvar.h   |  85 ++++++++++++++
 sys/include/arch/amd64/msr.h        |   1 +
 7 files changed, 356 insertions(+), 1 deletion(-)
 create mode 100644 sys/arch/amd64/amd64/lapic.c
 create mode 100644 sys/include/arch/amd64/lapic.h
 create mode 100644 sys/include/arch/amd64/lapicvar.h

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c
index d1686df..3bcdc9d 100644
--- a/sys/arch/amd64/amd64/acpi_machdep.c
+++ b/sys/arch/amd64/amd64/acpi_machdep.c
@@ -33,6 +33,7 @@
 #include <dev/acpi/acpivar.h>
 #include <dev/acpi/tables.h>
 #include <machine/ioapic.h>
+#include <machine/lapic.h>
 
 #define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__)
 
@@ -50,6 +51,7 @@ acpi_init_madt(void)
 
     cur = (uint8_t *)(madt + 1);
     end = (uint8_t *)madt + madt->hdr.length;
+    g_lapic_base = madt->lapic_addr;
 
     while (cur < end) {
         apichdr = (void *)cur;
diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
new file mode 100644
index 0000000..f61715d
--- /dev/null
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2023-2024 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/param.h>
+#include <sys/types.h>
+#include <sys/panic.h>
+#include <sys/mmio.h>
+#include <sys/syslog.h>
+#include <machine/lapicvar.h>
+#include <machine/lapic.h>
+#include <machine/cpuid.h>
+#include <machine/cpu.h>
+#include <machine/msr.h>
+
+#define pr_trace(fmt, ...) kprintf("lapic: " fmt, ##__VA_ARGS__)
+
+/*
+ * Only calls pr_trace if we are the BSP.
+ */
+#define bsp_trace(...) do {                     \
+        uint64_t msr_val;                       \
+                                                \
+        msr_val = rdmsr(IA32_APIC_BASE_MSR);    \
+        if (ISSET(msr_val, BIT(8))) {           \
+            pr_trace(__VA_ARGS__);              \
+        }                                       \
+    } while (0);
+
+uintptr_t g_lapic_base = 0;
+
+/*
+ * Returns true if LAPIC is supported.
+ *
+ * LAPIC is supported if CPUID.(EAX=1H):EDX[9] == 1
+ */
+static inline bool
+lapic_supported(void)
+{
+    uint32_t eax, edx, tmp;
+
+    CPUID(0x00000001, eax, tmp, tmp, edx);
+    return ISSET(edx, BIT(9));
+}
+
+/*
+ * Checks if the processor supports x2APIC
+ * mode. Returns true if so.
+ */
+static inline bool
+lapic_has_x2apic(void)
+{
+    uint32_t ecx, tmp;
+
+    CPUID(0x00000001, tmp, tmp, ecx, tmp);
+    return ISSET(ecx, BIT(21));
+}
+
+/*
+ * Reads a 32 bit value from Local APIC
+ * register space.
+ *
+ * @reg: Register to read from.
+ */
+static inline uint64_t
+lapic_readl(uint32_t reg)
+{
+    void *addr;
+    const struct cpu_info *ci = this_cpu();
+
+    if (!ci->has_x2apic) {
+        addr = (void *)(g_lapic_base + reg);
+        return mmio_read32(addr);
+    } else {
+        reg >>= 4;
+        return rdmsr(x2APIC_MSR_BASE + reg);
+    }
+}
+
+/*
+ * Writes a 32 bit value to Local APIC
+ * register space.
+ *
+ * @reg: Register to write to.
+ */
+static inline void
+lapic_writel(uint32_t reg, uint64_t val)
+{
+    void *addr;
+    const struct cpu_info *ci = this_cpu();
+
+    if (!ci->has_x2apic) {
+        addr = (void *)(g_lapic_base + reg);
+        mmio_write32(addr, val);
+    } else {
+        reg >>= 4;
+        wrmsr(x2APIC_MSR_BASE + reg, val);
+    }
+}
+
+/*
+ * Set bits within a LAPIC register
+ * without overwriting the whole thing.
+ *
+ * @reg: Reg with bits to be set.
+ * @value: Value in reg will be ORd with this.
+ */
+static inline void
+lapic_reg_set(uint32_t reg, uint32_t value)
+{
+    uint32_t old;
+
+    old = lapic_readl(reg);
+    lapic_writel(reg, old | value);
+}
+
+/*
+ * Clear bits within a LAPIC register
+ * without overwriting the whole thing.
+ *
+ * @reg: Reg with bits to be cleared.
+ * @value: Value in reg will be cleared by this value.
+ */
+static inline void
+lapic_reg_clear(uint32_t reg, uint32_t value)
+{
+    uint32_t old;
+
+    old = lapic_readl(reg);
+    lapic_writel(reg, old & ~(value));
+}
+
+/*
+ * Hardware and software enable the Local APIC
+ * through IA32_APIC_BASE_MSR
+ */
+static inline void
+lapic_enable(const struct cpu_info *ci)
+{
+    uint64_t tmp;
+
+    /* Hardware enable the Local APIC */
+    tmp = rdmsr(IA32_APIC_BASE_MSR);
+    tmp |= ci->has_x2apic << x2APIC_ENABLE_SHIFT;
+    wrmsr(IA32_APIC_BASE_MSR, tmp | LAPIC_HW_ENABLE);
+
+    /* Software enable the Local APIC */
+    lapic_reg_set(LAPIC_SVR, LAPIC_SW_ENABLE);
+}
+
+/*
+ * Reads the Local APIC ID of the current
+ * processor.
+ */
+static inline uint32_t
+lapic_read_id(const struct cpu_info *ci)
+{
+    if (!ci->has_x2apic) {
+        return (lapic_readl(LAPIC_ID) >> 24) & 0xF;
+    } else {
+        return lapic_readl(LAPIC_ID);
+    }
+}
+
+void
+lapic_init(void)
+{
+    struct cpu_info *ci = this_cpu();
+
+    /*
+     * Hyra currently depends on the existance
+     * of a Local APIC.
+     */
+    if (!lapic_supported()) {
+        panic("This machine does not support LAPIC!\n");
+    }
+
+    /* Ensure the LAPIC base is valid */
+    if (g_lapic_base == 0) {
+        panic("Invalid LAPIC base\n");
+    }
+
+    ci->has_x2apic = lapic_has_x2apic();
+    lapic_enable(ci);
+
+    ci->apicid = lapic_read_id(ci);
+    bsp_trace("BSP LAPIC enabled in %s mode (id=%d)\n",
+        ci->has_x2apic ? "x2APIC" : "xAPIC", ci->apicid);
+}
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 275c23e..983a480 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -34,6 +34,7 @@
 #include <machine/trap.h>
 #include <machine/asm.h>
 #include <machine/cpuid.h>
+#include <machine/lapic.h>
 
 #if defined(__SPECTRE_IBRS)
 #define SPECTRE_IBRS  __SPECTRE_IBRS
@@ -76,6 +77,16 @@ try_mitigate_spectre(void)
     ibrs_enable();
 }
 
+/*
+ * Get the descriptor for the currently
+ * running processor.
+ */
+struct cpu_info *
+this_cpu(void)
+{
+    return (void *)amd64_read_gs_base();
+}
+
 void
 cpu_startup(void)
 {
@@ -84,5 +95,7 @@ cpu_startup(void)
 
     setup_vectors();
     amd64_write_gs_base((uintptr_t)&g_bsp_ci);
+
     try_mitigate_spectre();
+    lapic_init();
 }
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index efa60ad..4e5baf1 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -35,9 +35,10 @@
 
 struct cpu_info {
     uint32_t apicid;
+    uint8_t has_x2apic : 1;
 };
 
 void cpu_startup(void);
-
+struct cpu_info *this_cpu(void);
 
 #endif  /* !_MACHINE_CPU_H_ */
diff --git a/sys/include/arch/amd64/lapic.h b/sys/include/arch/amd64/lapic.h
new file mode 100644
index 0000000..8a6bb14
--- /dev/null
+++ b/sys/include/arch/amd64/lapic.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_LAPIC_H_
+#define _MACHINE_LAPIC_H_
+
+#include <sys/types.h>
+
+void lapic_init(void);
+
+extern uintptr_t g_lapic_base;
+
+#endif  /* !_MACHINE_LAPIC_H_ */
diff --git a/sys/include/arch/amd64/lapicvar.h b/sys/include/arch/amd64/lapicvar.h
new file mode 100644
index 0000000..e224e43
--- /dev/null
+++ b/sys/include/arch/amd64/lapicvar.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_LAPICVAR_H_
+#define _MACHINE_LAPICVAR_H_
+
+#include <sys/param.h>
+
+/* LAPIC register offsets */
+#define LAPIC_ID            0x0020U     /* ID Register */
+#define LAPIC_VERSION       0x0030U     /* Version Register */
+#define LAPIC_TPR           0x0080U     /* Task Priority Register */
+#define LAPIC_APR           0x0090U     /* Arbitration Priority Register */
+#define LAPIC_PPR           0x00A0U     /* Processor Priority Register */
+#define LAPIC_EOI           0x00B0U     /* End Of Interrupt Register */
+#define LAPIC_RRD           0x00C0U     /* Remote Read Register */
+#define LAPIC_LDR           0x00D0U     /* Logical Destination Register */
+#define LAPIC_DFR           0x00E0U     /* Destination Format Register */
+#define LAPIC_SVR           0x00F0U     /* Spurious Vector Register */
+#define LAPIC_ISR           0x0100U     /* In service register (max=0x0220) */
+#define LAPIC_TMR           0x0180U     /* Trigger Mode Register (max=0x0220) */
+#define LAPIC_IRR           0x0200U     /* Interrupt Request Register (max=0x0270) */
+#define LAPIC_ERR           0x0280U     /* Error Status Register */
+#define LAPIC_ICRLO         0x0300U     /* Interrupt Command Low Register */
+#define LAPIC_ICRHI         0x0310U     /* Interrupt Command High Register */
+#define LAPIC_LVT_TMR       0x0320U     /* LVT Timer Register */
+#define LAPIC_DCR           0x03E0U     /* Divide Configuration Register (for timer) */
+#define LAPIC_INIT_CNT      0x0380U     /* Initial Count Register (for timer) */
+#define LAPIC_CUR_CNT       0x0390U     /* Current Count Register (for timer) */
+
+/*
+ * The x2APIC register space is accessed via
+ * RDMSR/WRMSR instructions. The below defines
+ * the base MSR address for the register space.
+ */
+#define x2APIC_MSR_BASE 0x00000800
+
+/*
+ * To hardware enable, OR the value of the IA32_APIC_BASE
+ * MSR with LAPIC_HW_ENABLE and rewrite it.
+ *
+ * To software enable, OR the value of the SVR with
+ * LAPIC_SW_ENABLE and rewrite it.
+ *
+ * LAPIC_SW_ENABLE has the low 8 bits set as some hardware
+ * requires the spurious vector to be hardwired to 1s so
+ * we'll go with that to be safe.
+ */
+#define LAPIC_HW_ENABLE     BIT(11)
+#define LAPIC_SW_ENABLE     (BIT(8) | 0xFF)
+#define x2APIC_ENABLE_SHIFT 10
+
+/* LVT bits */
+#define LAPIC_LVT_MASK            BIT(16)
+#define LVT_TMR_ONESHOT           0x00
+#define LVT_TMR_PERIODIC          0x01
+#define LVT_TMR_TSC_DEADLINE      0x02
+
+#endif  /* !_MACHINE_LAPICVAR_H_ */
diff --git a/sys/include/arch/amd64/msr.h b/sys/include/arch/amd64/msr.h
index 6ad95f1..d3d0c9a 100644
--- a/sys/include/arch/amd64/msr.h
+++ b/sys/include/arch/amd64/msr.h
@@ -32,6 +32,7 @@
 
 #define IA32_SPEC_CTL       0x00000048
 #define IA32_KERNEL_GS_BASE 0xC0000102
+#define IA32_APIC_BASE_MSR  0x0000001B
 
 #if !defined(__ASSEMBLER__)
 static inline uint64_t
-- 
cgit v1.2.3


From b24d9a83b20a7cae49af41031a8e54946f7d42b6 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Thu, 6 Jun 2024 15:12:32 -0400
Subject: kernel/amd64: isa: Add i8254 driver

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/isa/i8254.c         | 73 ++++++++++++++++++++++++++++++++++++++
 sys/include/arch/amd64/isa/i8254.h | 44 +++++++++++++++++++++++
 2 files changed, 117 insertions(+)
 create mode 100644 sys/arch/amd64/isa/i8254.c
 create mode 100644 sys/include/arch/amd64/isa/i8254.h

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/isa/i8254.c b/sys/arch/amd64/isa/i8254.c
new file mode 100644
index 0000000..b5ceb9c
--- /dev/null
+++ b/sys/arch/amd64/isa/i8254.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2023-2024 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/param.h>
+#include <machine/isa/i8254.h>
+#include <machine/pio.h>
+
+/*
+ * Fetches the current count.
+ */
+uint16_t
+i8254_get_count(void)
+{
+    uint8_t lo, hi;
+
+    outb(I8254_COMMAND, 0x00);
+    lo = inb(0x40);
+    hi = inb(0x40);
+    return COMBINE8(hi, lo);
+}
+
+/*
+ * Set the reload value
+ *
+ * The reload value is where the i8254's counter
+ * starts...
+ */
+void
+i8254_set_reload(uint16_t val)
+{
+    outb(I8254_COMMAND, 0x34);
+    outb(0x40, (val & 0xFF));
+    outb(0x40, (val >> 8) & 0xFF);
+}
+
+void
+i8254_set_frequency(uint64_t freq_hz)
+{
+    uint64_t divisor = I8254_DIVIDEND / freq_hz;
+
+    if ((I8254_DIVIDEND % freq_hz) > (freq_hz / 2)) {
+        ++divisor;
+    }
+
+    i8254_set_reload(freq_hz);
+}
diff --git a/sys/include/arch/amd64/isa/i8254.h b/sys/include/arch/amd64/isa/i8254.h
new file mode 100644
index 0000000..1463d71
--- /dev/null
+++ b/sys/include/arch/amd64/isa/i8254.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_ISA_I8254_H_
+#define _MACHINE_ISA_I8254_H_
+
+#include <sys/types.h>
+
+#define I8254_COMMAND     0x43
+#define I8254_CHANNEL_0   0x40
+#define I8254_CHANNEL_2   0x42
+#define I8254_DIVIDEND    1193182ULL
+
+uint16_t i8254_get_count(void);
+void i8254_set_reload(uint16_t val);
+void i8254_set_frequency(uint64_t frequency_hz);
+
+#endif  /* !_MACHINE_ISA_I8254_H_ */
-- 
cgit v1.2.3


From 8603f1242b54d2f39e4e618ebc98a1e8bbab8164 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Thu, 6 Jun 2024 15:49:34 -0400
Subject: kernel/amd64: intr: Add intr_alloc_vector()

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/intr.c   | 43 +++++++++++++++++++++++++++++++++++++++++++
 sys/include/arch/amd64/intr.h | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/intr.c
 create mode 100644 sys/include/arch/amd64/intr.h

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c
new file mode 100644
index 0000000..b841da7
--- /dev/null
+++ b/sys/arch/amd64/amd64/intr.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023-2024 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 <machine/intr.h>
+
+int
+intr_alloc_vector(void)
+{
+    static size_t vec = 0x21;
+
+    if (vec >= 0xFF) {
+        return -1;
+    }
+
+    return vec++;
+}
diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h
new file mode 100644
index 0000000..cceab6f
--- /dev/null
+++ b/sys/include/arch/amd64/intr.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_INTR_H_
+#define _MACHINE_INTR_H_
+
+#include <sys/types.h>
+
+int intr_alloc_vector(void);
+
+#endif
-- 
cgit v1.2.3


From 79afbbb41dee4bb24d2cad8234beacbd7a7e7a9b Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Thu, 6 Jun 2024 15:50:23 -0400
Subject: kernel/amd64: lapic: Add support for LAPIC timer

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/lapic.c      | 109 ++++++++++++++++++++++++++++++++++++++
 sys/arch/amd64/amd64/lapic_intr.S |   9 ++++
 sys/include/arch/amd64/cpu.h      |   1 +
 3 files changed, 119 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/lapic_intr.S

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index f61715d..823e830 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -32,11 +32,15 @@
 #include <sys/panic.h>
 #include <sys/mmio.h>
 #include <sys/syslog.h>
+#include <dev/timer.h>
+#include <machine/intr.h>
+#include <machine/isa/i8254.h>
 #include <machine/lapicvar.h>
 #include <machine/lapic.h>
 #include <machine/cpuid.h>
 #include <machine/cpu.h>
 #include <machine/msr.h>
+#include <machine/idt.h>
 
 #define pr_trace(fmt, ...) kprintf("lapic: " fmt, ##__VA_ARGS__)
 
@@ -52,8 +56,12 @@
         }                                       \
     } while (0);
 
+static struct timer lapic_timer;
+static uint8_t lapic_timer_vec = 0;
 uintptr_t g_lapic_base = 0;
 
+void lapic_tmr_isr(void);
+
 /*
  * Returns true if LAPIC is supported.
  *
@@ -123,6 +131,62 @@ lapic_writel(uint32_t reg, uint64_t val)
     }
 }
 
+/*
+ * Starts the Local APIC countdown timer...
+ *
+ * @mask: True to mask timer.
+ * @mode: Timer mode.
+ * @count: Count to start at.
+ */
+static inline void
+lapic_timer_start(bool mask, uint8_t mode, uint32_t count)
+{
+    uint32_t tmp;
+
+    tmp = (mode << 17) | (mask << 16) | lapic_timer_vec;
+    lapic_writel(LAPIC_LVT_TMR, tmp);
+    lapic_writel(LAPIC_DCR, 0);
+    lapic_writel(LAPIC_INIT_CNT, count);
+}
+
+/*
+ * Start Local APIC timer oneshot with number
+ * of ticks to count down from.
+ *
+ * @mask: If `true', timer will be masked, `count' should be 0.
+ * @count: Number of ticks.
+ */
+static void
+lapic_timer_oneshot(bool mask, uint32_t count)
+{
+    lapic_timer_start(mask, LVT_TMR_ONESHOT, count);
+}
+
+/*
+ * Start Local APIC timer oneshot in microseconds.
+ *
+ * @us: Microseconds.
+ */
+static void
+lapic_timer_oneshot_us(size_t usec)
+{
+    uint64_t ticks;
+    struct cpu_info *ci = this_cpu();
+
+    ticks = usec * (ci->lapic_tmr_freq / 1000000);
+    lapic_timer_oneshot(false, ticks);
+}
+
+/*
+ * Stops the Local APIC timer
+ */
+static void
+lapic_timer_stop(void)
+{
+    lapic_writel(LAPIC_LVT_TMR, LAPIC_LVT_MASK);
+    lapic_writel(LAPIC_INIT_CNT, 0);
+}
+
 /*
  * Set bits within a LAPIC register
  * without overwriting the whole thing.
@@ -187,10 +251,37 @@ lapic_read_id(const struct cpu_info *ci)
     }
 }
 
+/*
+ * Init the Local APIC timer and return
+ * the frequency.
+ */
+static size_t
+lapic_timer_init(void)
+{
+    uint16_t ticks_start, ticks_end;
+    size_t ticks_total, freq;
+    const uint16_t MAX_SAMPLES = 0xFFFF;
+
+    lapic_timer_stop();
+    i8254_set_reload(MAX_SAMPLES);
+    ticks_start = i8254_get_count();
+
+    lapic_writel(LAPIC_INIT_CNT, MAX_SAMPLES);
+    while (lapic_readl(LAPIC_CUR_CNT) != 0);
+
+    ticks_end = i8254_get_count();
+    ticks_total = ticks_start - ticks_end;
+
+    freq = (MAX_SAMPLES / ticks_total) * I8254_DIVIDEND;
+    lapic_timer_stop();
+    return freq;
+}
+
 void
 lapic_init(void)
 {
     struct cpu_info *ci = this_cpu();
+    tmrr_status_t tmr_status;
 
     /*
      * Hyra currently depends on the existance
@@ -200,6 +291,12 @@ lapic_init(void)
         panic("This machine does not support LAPIC!\n");
     }
 
+    /* Allocate a vector if needed */
+    if (lapic_timer_vec == 0) {
+        lapic_timer_vec = intr_alloc_vector();
+        idt_set_desc(lapic_timer_vec, IDT_INT_GATE, ISR(lapic_tmr_isr), 0);
+    }
+
     /* Ensure the LAPIC base is valid */
     if (g_lapic_base == 0) {
         panic("Invalid LAPIC base\n");
@@ -209,6 +306,18 @@ lapic_init(void)
     lapic_enable(ci);
 
     ci->apicid = lapic_read_id(ci);
+    ci->lapic_tmr_freq = lapic_timer_init();
     bsp_trace("BSP LAPIC enabled in %s mode (id=%d)\n",
         ci->has_x2apic ? "x2APIC" : "xAPIC", ci->apicid);
+
+    /* Try to register the timer */
+    lapic_timer.name = "LAPIC_INTEGRATED_TIMER";
+    lapic_timer.stop = lapic_timer_stop;
+    lapic_timer.oneshot_us = lapic_timer_oneshot_us;
+    tmr_status = register_timer(TIMER_SCHED, &lapic_timer);
+
+    /* This should not happen but handle it just in case */
+    if (__unlikely(tmr_status != TMRR_SUCCESS)) {
+        panic("Failed to register %s\n", lapic_timer.name);
+    }
 }
diff --git a/sys/arch/amd64/amd64/lapic_intr.S b/sys/arch/amd64/amd64/lapic_intr.S
new file mode 100644
index 0000000..295de2d
--- /dev/null
+++ b/sys/arch/amd64/amd64/lapic_intr.S
@@ -0,0 +1,9 @@
+#include <machine/frameasm.h>
+
+    .text
+    .globl lapic_tmr_isr
+lapic_tmr_isr:
+    push_trapframe $0
+    mov %rsp, %rdi
+    pop_trapframe
+    iretq
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index 4e5baf1..92d2356 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -36,6 +36,7 @@
 struct cpu_info {
     uint32_t apicid;
     uint8_t has_x2apic : 1;
+    size_t lapic_tmr_freq;
 };
 
 void cpu_startup(void);
-- 
cgit v1.2.3


From a84cacff59d6e31c05b6f9eddebf28dbb418b303 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Thu, 6 Jun 2024 17:46:39 -0400
Subject: kernel/amd64: tss: Add support for TSS

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/machdep.c |  12 +++
 sys/arch/amd64/amd64/tss.c     | 177 +++++++++++++++++++++++++++++++++++++++++
 sys/include/arch/amd64/cpu.h   |   2 +
 sys/include/arch/amd64/gdt.h   |   1 +
 sys/include/arch/amd64/intr.h  |   4 +
 sys/include/arch/amd64/tss.h   | 121 ++++++++++++++++++++++++++++
 6 files changed, 317 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/tss.c
 create mode 100644 sys/include/arch/amd64/tss.h

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 983a480..2fe71a9 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <machine/cpu.h>
 #include <machine/gdt.h>
+#include <machine/tss.h>
 #include <machine/idt.h>
 #include <machine/trap.h>
 #include <machine/asm.h>
@@ -67,6 +68,16 @@ setup_vectors(void)
     idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0);
 }
 
+static inline void
+init_tss(struct cpu_info *ci)
+{
+    struct tss_desc *desc;
+
+    desc = (struct tss_desc *)&g_gdt_data[GDT_TSS];
+    write_tss(ci, desc);
+    tss_load();
+}
+
 static void
 try_mitigate_spectre(void)
 {
@@ -95,6 +106,7 @@ cpu_startup(void)
 
     setup_vectors();
     amd64_write_gs_base((uintptr_t)&g_bsp_ci);
+    init_tss(&g_bsp_ci);
 
     try_mitigate_spectre();
     lapic_init();
diff --git a/sys/arch/amd64/amd64/tss.c b/sys/arch/amd64/amd64/tss.c
new file mode 100644
index 0000000..5aab74a
--- /dev/null
+++ b/sys/arch/amd64/amd64/tss.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2023-2024 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/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/panic.h>
+#include <vm/dynalloc.h>
+#include <vm/physmem.h>
+#include <machine/tss.h>
+#include <machine/cpu.h>
+#include <assert.h>
+#include <string.h>
+
+/*
+ * Allocates memory for TSS and kernel
+ * stack.
+ *
+ * XXX: Kernel stack is allocated from
+ *      vm_alloc_frame()
+ */
+static void
+alloc_resources(struct cpu_info *ci)
+{
+    const size_t STACK_SIZE = 0x1000;
+    struct tss_entry *tss;
+    static uintptr_t rsp0_base, rsp0;
+
+    if (ci->tss == NULL) {
+        tss = dynalloc(sizeof(*tss));
+
+        if (tss == NULL) {
+            panic("Failed to alloc TSS\n");
+        }
+
+        memset(tss, 0, sizeof(*tss));
+        rsp0_base = vm_alloc_frame(1);
+
+        if (rsp0_base == 0) {
+            panic("Could not allocate RSP0 base\n");
+        }
+
+        rsp0 = rsp0_base + STACK_SIZE;
+        tss->rsp0_lo = rsp0 & 0xFFFFFFFF;
+        tss->rsp0_hi = (rsp0 >> 32) & 0xFFFFFFFF;
+        ci->tss = tss;
+    }
+}
+
+/*
+ * Update interrupt stack table entry `istno' with `stack'
+ *
+ * @stack: Interrupt stack.
+ * @istno: IST number, must be 1-based.
+ *
+ * Returns 0 on success.
+ */
+int
+tss_update_ist(struct cpu_info *ci, union tss_stack stack, uint8_t istno)
+{
+    volatile struct tss_entry *tss = ci->tss;
+
+    __assert(tss != NULL);
+
+    switch (istno) {
+    case 1:
+        tss->ist1_lo = stack.top_lo;
+        tss->ist1_hi = stack.top_hi;
+        break;
+    case 2:
+        tss->ist2_lo = stack.top_lo;
+        tss->ist2_hi = stack.top_hi;
+        break;
+    case 3:
+        tss->ist3_lo = stack.top_lo;
+        tss->ist3_hi = stack.top_hi;
+        break;
+    case 4:
+        tss->ist4_lo = stack.top_lo;
+        tss->ist4_hi = stack.top_hi;
+        break;
+    case 5:
+        tss->ist5_lo = stack.top_lo;
+        tss->ist5_hi = stack.top_hi;
+        break;
+    case 6:
+        tss->ist6_lo = stack.top_lo;
+        tss->ist6_hi = stack.top_hi;
+        break;
+    case 7:
+        tss->ist7_lo = stack.top_lo;
+        tss->ist7_hi = stack.top_hi;
+        break;
+    default:
+        return -EINVAL;
+    };
+
+    return 0;
+}
+
+/*
+ * Allocates TSS stack.
+ *
+ * @entry_out: Pointer to location where allocated entry
+ *             will be sent.
+ *
+ * Returns 0 on success.
+ */
+int
+tss_alloc_stack(union tss_stack *entry_out, size_t size)
+{
+    uintptr_t base = (uintptr_t)dynalloc(size);
+
+    if (base == 0) {
+        return -ENOMEM;
+    }
+
+    entry_out->top = base + size;
+    return 0;
+}
+
+void
+write_tss(struct cpu_info *ci, struct tss_desc *desc)
+{
+    volatile struct tss_entry *tss;
+    uintptr_t tss_base;
+
+    alloc_resources(ci);
+    tss_base = (uintptr_t)ci->tss;
+
+    /*
+     * XXX: The AVL (Available for use by system software)
+     *      bit is ignored by hardware and it is up to us
+     *      to decide how to use it... As of now, it is useless
+     *      to us and shall remain 0.
+     */
+    desc->seglimit = sizeof(struct tss_entry);
+    desc->p = 1;        /* Must be present to be valid! */
+    desc->g = 0;        /* Granularity -> 0 */
+    desc->avl = 0;      /* Not used */
+    desc->dpl = 0;      /* Descriptor Privilege Level -> 0 */
+    desc->type = 0x9;   /* For TSS -> 0x9 (0b1001) */
+
+    desc->base_lo16 =       tss_base & 0xFFFF;
+    desc->base_mid8 =       (tss_base >> 16) & 0xFF;
+    desc->base_hi_mid8 =    (tss_base >> 24) & 0xFF;
+    desc->base_hi32 =       (tss_base >> 32) & 0xFFFFFFFF;
+
+    tss = ci->tss;
+    tss->io_base = 0xFF;    /* Disallow ring 3 port I/O  */
+}
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index 92d2356..ef2eb78 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -32,11 +32,13 @@
 
 #include <sys/types.h>
 #include <sys/cdefs.h>
+#include <machine/tss.h>
 
 struct cpu_info {
     uint32_t apicid;
     uint8_t has_x2apic : 1;
     size_t lapic_tmr_freq;
+    struct tss_entry *tss;
 };
 
 void cpu_startup(void);
diff --git a/sys/include/arch/amd64/gdt.h b/sys/include/arch/amd64/gdt.h
index 6f8a914..ce7dd60 100644
--- a/sys/include/arch/amd64/gdt.h
+++ b/sys/include/arch/amd64/gdt.h
@@ -6,6 +6,7 @@
 
 #define KERNEL_CS 0x08
 #define KERNEL_DS 0x10
+#define GDT_TSS 5
 
 struct __packed gdt_entry {
     uint16_t limit;
diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h
index cceab6f..3f0da77 100644
--- a/sys/include/arch/amd64/intr.h
+++ b/sys/include/arch/amd64/intr.h
@@ -32,6 +32,10 @@
 
 #include <sys/types.h>
 
+#define IST_SCHED   1U
+#define IST_HW_IRQ  2U
+#define IST_SW_INT  3U
+
 int intr_alloc_vector(void);
 
 #endif
diff --git a/sys/include/arch/amd64/tss.h b/sys/include/arch/amd64/tss.h
new file mode 100644
index 0000000..347192d
--- /dev/null
+++ b/sys/include/arch/amd64/tss.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_TSS_H_
+#define _MACHINE_TSS_H_
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+struct cpu_info;
+
+/*
+ * A TSS entry (64-bit)
+ *
+ * See Intel SDM Section 8.2.1 - Task-State Segment (TSS)
+ */
+struct __packed tss_entry {
+    uint32_t reserved1;
+    uint32_t rsp0_lo;
+    uint32_t rsp0_hi;
+    uint32_t rsp1_lo;
+    uint32_t rsp1_hi;
+    uint32_t rsp2_lo;
+    uint32_t rsp2_hi;
+    uint64_t reserved2;
+    uint32_t ist1_lo;
+    uint32_t ist1_hi;
+    uint32_t ist2_lo;
+    uint32_t ist2_hi;
+    uint32_t ist3_lo;
+    uint32_t ist3_hi;
+    uint32_t ist4_lo;
+    uint32_t ist4_hi;
+    uint32_t ist5_lo;
+    uint32_t ist5_hi;
+    uint32_t ist6_lo;
+    uint32_t ist6_hi;
+    uint32_t ist7_lo;
+    uint32_t ist7_hi;
+    uint64_t reserved3;
+    uint16_t reserved4;
+    uint16_t io_base;
+};
+
+/*
+ * TSS descriptor (64-bit)
+ *
+ * The TSS descriptor describes the location
+ * of the TSS segments among other things...
+ *
+ * See Intel SDM Section 8.2.3 - TSS Descriptor in 64-bit mode
+ */
+struct __packed tss_desc {
+    uint16_t seglimit;
+    uint16_t base_lo16;
+    uint8_t base_mid8;
+    uint8_t type        : 4;
+    uint8_t zero        : 1;
+    uint8_t dpl         : 2;
+    uint8_t p           : 1;
+    uint8_t seglimit_hi : 4;
+    uint8_t avl         : 1;
+    uint8_t unused      : 2;
+    uint8_t g           : 1;
+    uint8_t base_hi_mid8;
+    uint32_t base_hi32;
+    uint32_t reserved;
+};
+
+/*
+ * Holds the address of the address pointing
+ * to the top of an interrupt stack.
+ */
+union tss_stack {
+    struct {
+        uint32_t top_lo;
+        uint32_t top_hi;
+    };
+    uint64_t top;
+};
+
+__always_inline static inline void
+tss_load(void)
+{
+    __ASMV("str %ax\n"
+           "mov $0x2B, %ax\n"
+           "ltr %ax"
+    );
+}
+
+int tss_alloc_stack(union tss_stack *entry_out, size_t size);
+int tss_update_ist(struct cpu_info *ci, union tss_stack stack, uint8_t istno);
+void write_tss(struct cpu_info *ci, struct tss_desc *desc);
+
+#endif  /* !_MACHINE_TSS_H_ */
-- 
cgit v1.2.3


From 19e1b54d12edbe80419b7fde9c602833544eb7ab Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Thu, 6 Jun 2024 17:47:26 -0400
Subject: kernel/amd64: lapic: Assign timer to IST_SCHED

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/lapic.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index 823e830..3a87b74 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -41,6 +41,7 @@
 #include <machine/cpu.h>
 #include <machine/msr.h>
 #include <machine/idt.h>
+#include <machine/tss.h>
 
 #define pr_trace(fmt, ...) kprintf("lapic: " fmt, ##__VA_ARGS__)
 
@@ -281,6 +282,7 @@ void
 lapic_init(void)
 {
     struct cpu_info *ci = this_cpu();
+    union tss_stack tmr_stack;
     tmrr_status_t tmr_status;
 
     /*
@@ -291,10 +293,18 @@ lapic_init(void)
         panic("This machine does not support LAPIC!\n");
     }
 
+    /* Try to allocate LAPIC timer interrupt stack */
+    if (tss_alloc_stack(&tmr_stack, DEFAULT_PAGESIZE) != 0) {
+        panic("Failed to allocate LAPIC TMR stack!\n");
+    }
+
+    tss_update_ist(ci, tmr_stack, IST_SCHED);
+
     /* Allocate a vector if needed */
     if (lapic_timer_vec == 0) {
         lapic_timer_vec = intr_alloc_vector();
-        idt_set_desc(lapic_timer_vec, IDT_INT_GATE, ISR(lapic_tmr_isr), 0);
+        idt_set_desc(lapic_timer_vec, IDT_INT_GATE, ISR(lapic_tmr_isr),
+            IST_SCHED);
     }
 
     /* Ensure the LAPIC base is valid */
-- 
cgit v1.2.3


From f8ce8234aa7247c8f3a4317f5671b5fd40ffb8c8 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Fri, 7 Jun 2024 21:25:10 -0400
Subject: kernel: Add __cacheline_aligned macro

This commit introduces a "__cacheline_aligned" macro which aligns data
by the cache line size (COHERENCY_UNIT bytes). This is useful for
heavily contended locks.

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/conf/link.ld |  8 +++++++-
 sys/include/sys/cdefs.h     | 17 +++++++++++++++++
 sys/include/sys/param.h     |  5 +++++
 3 files changed, 29 insertions(+), 1 deletion(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/conf/link.ld b/sys/arch/amd64/conf/link.ld
index b073054..9c47a81 100644
--- a/sys/arch/amd64/conf/link.ld
+++ b/sys/arch/amd64/conf/link.ld
@@ -32,7 +32,7 @@ SECTIONS
     . += CONSTANT(MAXPAGESIZE);
 
     .data : {
-        *(.data .data.*)
+        *(.data)
     } :data
 
     .bss : {
@@ -40,6 +40,12 @@ SECTIONS
         *(.bss .bss.*)
     } :data
 
+    /* -- Cache line alignment -- */
+    . = ALIGN(64);
+    .data.cacheline_aligned : {
+        *(.data.cacheline_aligned)
+    }
+
     /DISCARD/ : {
         *(.eh_frame)
         *(.note .note.*)
diff --git a/sys/include/sys/cdefs.h b/sys/include/sys/cdefs.h
index fc21750..655a023 100644
--- a/sys/include/sys/cdefs.h
+++ b/sys/include/sys/cdefs.h
@@ -30,10 +30,27 @@
 #ifndef _SYS_CDEFS_H_
 #define _SYS_CDEFS_H_
 
+#include <sys/param.h>
+
 #define __ASMV          __asm__ __volatile__
 #define __always_inline __attribute__((__always_inline__))
 #define __packed        __attribute__((__packed__))
 #define __likely(exp)   __builtin_expect(((exp) != 0), 1)
 #define __unlikely(exp) __builtin_expect(((exp) != 0), 0)
 
+#if defined(_KERNEL)
+/*
+ *  Align data on a cache line boundary. This is
+ *  mostly useful for certain locks to ensure they
+ *  have their own cache line to reduce contention.
+ *
+ */
+#ifndef __cacheline_aligned
+#define __cacheline_aligned                             \
+    __attribute__((__aligned__(COHERENCY_UNIT),         \
+                __section__(".data.cacheline_aligned")))
+
+#endif  /* __cacheline_aligned */
+#endif  /* _KERNEL */
+
 #endif  /* !_SYS_CDEFS_H_ */
diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h
index a35a094..483dc15 100644
--- a/sys/include/sys/param.h
+++ b/sys/include/sys/param.h
@@ -30,6 +30,11 @@
 #ifndef _SYS_PARAM_H_
 #define _SYS_PARAM_H_
 
+/* Assumed cache line size */
+#ifndef COHERENCY_UNIT
+#define COHERENCY_UNIT 64
+#endif
+
 /* Bit related macros */
 #define ISSET(v, f)  ((v) & (f))
 #define BIT(n) (1 << (n))
-- 
cgit v1.2.3


From aec200a3b8b4d5aabcc945536f9c872e7b4e4996 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sat, 8 Jun 2024 18:05:18 -0400
Subject: kernel/amd64: lapic: Serialize lapic_timer_init()

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/lapic.c | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index 3a87b74..7b3bd98 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -32,6 +32,7 @@
 #include <sys/panic.h>
 #include <sys/mmio.h>
 #include <sys/syslog.h>
+#include <sys/spinlock.h>
 #include <dev/timer.h>
 #include <machine/intr.h>
 #include <machine/isa/i8254.h>
@@ -262,6 +263,9 @@ lapic_timer_init(void)
     uint16_t ticks_start, ticks_end;
     size_t ticks_total, freq;
     const uint16_t MAX_SAMPLES = 0xFFFF;
+    static struct spinlock lock = {0};
+
+    spinlock_acquire(&lock);
 
     lapic_timer_stop();
     i8254_set_reload(MAX_SAMPLES);
@@ -275,6 +279,8 @@ lapic_timer_init(void)
 
     freq = (MAX_SAMPLES / ticks_total) * I8254_DIVIDEND;
     lapic_timer_stop();
+
+    spinlock_release(&lock);
     return freq;
 }
 
-- 
cgit v1.2.3


From 3651f2f603e254cfb32f4bd04980a7edd50fdc7d Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sat, 8 Jun 2024 18:11:48 -0400
Subject: kernel/amd64: lapic: Don't test register_timer()

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/lapic.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index 7b3bd98..07a9a49 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -289,7 +289,6 @@ lapic_init(void)
 {
     struct cpu_info *ci = this_cpu();
     union tss_stack tmr_stack;
-    tmrr_status_t tmr_status;
 
     /*
      * Hyra currently depends on the existance
@@ -330,10 +329,5 @@ lapic_init(void)
     lapic_timer.name = "LAPIC_INTEGRATED_TIMER";
     lapic_timer.stop = lapic_timer_stop;
     lapic_timer.oneshot_us = lapic_timer_oneshot_us;
-    tmr_status = register_timer(TIMER_SCHED, &lapic_timer);
-
-    /* This should not happen but handle it just in case */
-    if (__unlikely(tmr_status != TMRR_SUCCESS)) {
-        panic("Failed to register %s\n", lapic_timer.name);
-    }
+    register_timer(TIMER_SCHED, &lapic_timer);
 }
-- 
cgit v1.2.3


From d5381223cea600ff007069bc1313de142cd06972 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sat, 8 Jun 2024 18:13:42 -0400
Subject: kernel/amd64: lapic: Add End-Of-Interrupt helper

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/lapic.c   | 10 ++++++++++
 sys/include/arch/amd64/lapic.h |  1 +
 2 files changed, 11 insertions(+)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index 07a9a49..b7cefd4 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -284,6 +284,16 @@ lapic_timer_init(void)
     return freq;
 }
 
+/*
+ * Indicates that the current interrupt is finished
+ * being serviced.
+ */
+void
+lapic_eoi(void)
+{
+    lapic_writel(LAPIC_EOI, 0);
+}
+
 void
 lapic_init(void)
 {
diff --git a/sys/include/arch/amd64/lapic.h b/sys/include/arch/amd64/lapic.h
index 8a6bb14..d06bcc9 100644
--- a/sys/include/arch/amd64/lapic.h
+++ b/sys/include/arch/amd64/lapic.h
@@ -33,6 +33,7 @@
 #include <sys/types.h>
 
 void lapic_init(void);
+void lapic_eoi(void);
 
 extern uintptr_t g_lapic_base;
 
-- 
cgit v1.2.3


From 44ef655a0afc3d2c8aa305f94b412f9d89bec846 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sat, 8 Jun 2024 18:15:13 -0400
Subject: kernel/amd64: Pass CPU info to cpu_startup()

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/machdep.c | 9 +++++----
 sys/include/arch/amd64/cpu.h   | 3 ++-
 sys/kern/init_main.c           | 2 +-
 3 files changed, 8 insertions(+), 6 deletions(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 2fe71a9..82fa97b 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -45,7 +45,7 @@
 
 int ibrs_enable(void);
 
-static struct cpu_info g_bsp_ci = {0};
+struct cpu_info g_bsp_ci = {0};
 static struct gdtr bsp_gdtr = {
     .limit = sizeof(struct gdt_entry) * 256 - 1,
     .offset = (uintptr_t)&g_gdt_data[0]
@@ -99,15 +99,16 @@ this_cpu(void)
 }
 
 void
-cpu_startup(void)
+cpu_startup(struct cpu_info *ci)
 {
     gdt_load(&bsp_gdtr);
     idt_load();
 
     setup_vectors();
-    amd64_write_gs_base((uintptr_t)&g_bsp_ci);
-    init_tss(&g_bsp_ci);
+    amd64_write_gs_base((uintptr_t)ci);
+    init_tss(ci);
 
     try_mitigate_spectre();
+    __ASMV("sti");              /* Unmask interrupts */
     lapic_init();
 }
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index ef2eb78..84391ba 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -41,7 +41,8 @@ struct cpu_info {
     struct tss_entry *tss;
 };
 
-void cpu_startup(void);
+void cpu_startup(struct cpu_info *ci);
 struct cpu_info *this_cpu(void);
+extern struct cpu_info g_bsp_ci;
 
 #endif  /* !_MACHINE_CPU_H_ */
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 6f17227..94fa8c0 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -49,7 +49,7 @@ main(void)
     vm_init();
 
     /* Startup the BSP */
-    cpu_startup();
+    cpu_startup(&g_bsp_ci);
 
     /* Nothing left to do... halt */
     cpu_reboot(REBOOT_HALT);
-- 
cgit v1.2.3


From 55845113211400c9b1657ec3ce72b06a05efac4e Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sat, 8 Jun 2024 18:19:51 -0400
Subject: kernel/amd64: Prepare for scheduler

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/lapic_intr.S |   2 +
 sys/arch/amd64/amd64/mp.c         |  93 ++++++++++++++++++++++++++++++++++
 sys/arch/amd64/conf/GENERIC       |   3 ++
 sys/include/arch/amd64/cpu.h      |   4 ++
 sys/include/sys/proc.h            |  48 ++++++++++++++++++
 sys/include/sys/sched.h           |  39 +++++++++++++++
 sys/include/sys/schedvar.h        |  63 +++++++++++++++++++++++
 sys/kern/init_main.c              |   5 ++
 sys/kern/kern_sched.c             | 102 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 359 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/mp.c
 create mode 100644 sys/include/sys/proc.h
 create mode 100644 sys/include/sys/sched.h
 create mode 100644 sys/include/sys/schedvar.h
 create mode 100644 sys/kern/kern_sched.c

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/lapic_intr.S b/sys/arch/amd64/amd64/lapic_intr.S
index 295de2d..a3fa7e4 100644
--- a/sys/arch/amd64/amd64/lapic_intr.S
+++ b/sys/arch/amd64/amd64/lapic_intr.S
@@ -5,5 +5,7 @@
 lapic_tmr_isr:
     push_trapframe $0
     mov %rsp, %rdi
+    call sched_switch
+    call lapic_eoi
     pop_trapframe
     iretq
diff --git a/sys/arch/amd64/amd64/mp.c b/sys/arch/amd64/amd64/mp.c
new file mode 100644
index 0000000..9512aa6
--- /dev/null
+++ b/sys/arch/amd64/amd64/mp.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2023-2024 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/limine.h>
+#include <sys/syslog.h>
+#include <sys/spinlock.h>
+#include <sys/sched.h>
+#include <machine/cpu.h>
+#include <vm/dynalloc.h>
+#include <assert.h>
+#include <string.h>
+
+#define pr_trace(fmt, ...) kprintf("cpu_mp: " fmt, ##__VA_ARGS__)
+
+static volatile struct limine_smp_request g_smp_req = {
+    .id = LIMINE_SMP_REQUEST,
+    .revision = 0
+};
+
+static void
+ap_trampoline(struct limine_smp_info *si)
+{
+    struct spinlock lock = {0};
+    struct cpu_info *ci;
+
+    spinlock_acquire(&lock);
+    ci = dynalloc(sizeof(*ci));
+    __assert(ci != NULL);
+
+    memset(ci, 0, sizeof(*ci));
+    cpu_startup(ci);
+
+    spinlock_release(&lock);
+    sched_enter();
+
+    while (1);
+}
+
+void
+mp_bootstrap_aps(struct cpu_info *ci)
+{
+    struct limine_smp_response *resp = g_smp_req.response;
+    struct limine_smp_info **cpus;
+    size_t cpu_init_counter;
+
+    /* Should not happen */
+    __assert(resp != NULL);
+
+    cpus = resp->cpus;
+    cpu_init_counter = resp->cpu_count - 1;
+
+    if (resp->cpu_count == 1) {
+        pr_trace("CPU has 1 core, no APs to bootstrap...\n");
+        return;
+    }
+
+    pr_trace("Bootstrapping %d cores...\n", cpu_init_counter);
+    for (size_t i = 0; i < resp->cpu_count; ++i) {
+        if (ci->apicid == cpus[i]->lapic_id) {
+            pr_trace("Skip %d (BSP)... continue\n", ci->apicid);
+            continue;
+        }
+
+        cpus[i]->goto_address = ap_trampoline;
+    }
+}
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index ea6ba76..a7bbc81 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,2 +1,5 @@
 // Kernel options
 option SPECTRE_IBRS no
+
+// Kernel constants
+setval SCHED_NQUEUE 4
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index 84391ba..b5420a6 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -32,6 +32,7 @@
 
 #include <sys/types.h>
 #include <sys/cdefs.h>
+#include <sys/proc.h>
 #include <machine/tss.h>
 
 struct cpu_info {
@@ -39,10 +40,13 @@ struct cpu_info {
     uint8_t has_x2apic : 1;
     size_t lapic_tmr_freq;
     struct tss_entry *tss;
+    struct proc *curtd;
 };
 
 void cpu_startup(struct cpu_info *ci);
 struct cpu_info *this_cpu(void);
+void mp_bootstrap_aps(struct cpu_info *ci);
+
 extern struct cpu_info g_bsp_ci;
 
 #endif  /* !_MACHINE_CPU_H_ */
diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h
new file mode 100644
index 0000000..ba47a5c
--- /dev/null
+++ b/sys/include/sys/proc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2023-2024 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_PROC_H_
+#define _SYS_PROC_H_
+
+#include <sys/types.h>
+#include <sys/spinlock.h>
+#if defined(_KERNEL)
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#endif  /* _KERNEL */
+
+#if defined(_KERNEL)
+
+struct proc {
+    pid_t pid;
+    struct cpu_info *cpu;
+};
+
+#endif  /* _KERNEL */
+#endif  /* !_SYS_PROC_H_ */
diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h
new file mode 100644
index 0000000..33d546d
--- /dev/null
+++ b/sys/include/sys/sched.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2023-2024 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_SCHED_H_
+#define _SYS_SCHED_H_
+
+#if defined(_KERNEL)
+
+void sched_init(void);
+void sched_enter(void);
+
+#endif  /* _KERNEL */
+#endif  /* !_SYS_SCHED_H_ */
diff --git a/sys/include/sys/schedvar.h b/sys/include/sys/schedvar.h
new file mode 100644
index 0000000..00caeb4
--- /dev/null
+++ b/sys/include/sys/schedvar.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023-2024 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_SCHEDVAR_H_
+#define _SYS_SCHEDVAR_H_
+
+#include <sys/cdefs.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+
+#if defined(_KERNEL)
+#define DEFAULT_TIMESLICE_USEC 1050
+#define SHORT_TIMESLICE_USEC 10
+
+#define SCHED_POLICY_MLFQ 0x00U   /* Multilevel feedback queue */
+#define SCHED_POLICY_RR   0x01U   /* Round robin */
+
+typedef uint8_t sched_policy_t;
+
+/* Might be set by kconf(1) */
+#if defined(__SCHED_NQUEUE)
+#define SCHED_NQUEUE __SCHED_NQUEUE
+#else
+#define SCHED_NQUEUE 4
+#endif  /* __SCHED_NQUEUE */
+
+/* Ensure SCHED_NQUEUE is an acceptable value */
+__static_assert(SCHED_NQUEUE <= 8, "SCHED_NQUEUE exceeds max");
+__static_assert(SCHED_NQUEUE > 0, "SCHED_NQUEUE cannot be zero");
+
+struct sched_queue {
+    TAILQ_HEAD(, proc) q;
+    size_t nthread;
+};
+
+#endif  /* _KERNEL */
+#endif  /* !_SYS_SCHEDVAR_H_ */
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 94fa8c0..6018dfe 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -29,6 +29,7 @@
 
 #include <sys/reboot.h>
 #include <sys/syslog.h>
+#include <sys/sched.h>
 #include <dev/cons/cons.h>
 #include <dev/acpi/acpi.h>
 #include <machine/cpu.h>
@@ -51,6 +52,10 @@ main(void)
     /* Startup the BSP */
     cpu_startup(&g_bsp_ci);
 
+    /* Start scheduler and bootstrap APs */
+    sched_init();
+    mp_bootstrap_aps(&g_bsp_ci);
+
     /* Nothing left to do... halt */
     cpu_reboot(REBOOT_HALT);
     __builtin_unreachable();
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
new file mode 100644
index 0000000..b79d682
--- /dev/null
+++ b/sys/kern/kern_sched.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023-2024 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/sched.h>
+#include <sys/schedvar.h>
+#include <sys/cdefs.h>
+#include <sys/syslog.h>
+#include <machine/frame.h>
+#include <dev/timer.h>
+#include <assert.h>
+
+#define pr_trace(fmt, ...) kprintf("ksched: " fmt, ##__VA_ARGS__)
+
+void sched_switch(struct trapframe *tf);
+
+static sched_policy_t policy = SCHED_POLICY_RR;
+
+/*
+ * Thread ready queues - all threads ready to be
+ * scheduled should be added to the toplevel queue.
+ */
+static struct sched_queue qlist[SCHED_NQUEUE];
+
+/*
+ * Perform timer oneshot
+ */
+static inline void
+sched_oneshot(bool now)
+{
+    struct timer timer;
+    size_t usec = now ? SHORT_TIMESLICE_USEC : DEFAULT_TIMESLICE_USEC;
+    tmrr_status_t tmr_status;
+
+    tmr_status = req_timer(TIMER_SCHED, &timer);
+    __assert(tmr_status == TMRR_SUCCESS);
+
+    timer.oneshot_us(usec);
+}
+
+/*
+ * Perform a context switch.
+ *
+ * TODO
+ */
+void
+sched_switch(struct trapframe *tf)
+{
+    static struct spinlock lock = {0};
+
+    spinlock_acquire(&lock);
+    spinlock_release(&lock);
+    sched_oneshot(false);
+}
+
+/*
+ * Main scheduler loop
+ */
+void
+sched_enter(void)
+{
+    sched_oneshot(false);
+    for (;;);
+}
+
+void
+sched_init(void)
+{
+    /* Setup the queues */
+    for (int i = 0; i < SCHED_NQUEUE; ++i) {
+        TAILQ_INIT(&qlist[i].q);
+    }
+
+    pr_trace("Prepared %d queues (policy=0x%x)\n",
+        SCHED_NQUEUE, policy);
+}
-- 
cgit v1.2.3


From 92cc282d121c2f5b842a661dae9cf4cb199c4d46 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sun, 9 Jun 2024 22:03:12 -0400
Subject: kernel/amd64: pmap: Add initial pmap code

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/pmap.c  | 236 +++++++++++++++++++++++++++++++++++++++++++
 sys/include/arch/amd64/tlb.h |  42 ++++++++
 sys/include/arch/amd64/vas.h |  46 +++++++++
 sys/include/vm/pmap.h        |  64 ++++++++++++
 4 files changed, 388 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/pmap.c
 create mode 100644 sys/include/arch/amd64/tlb.h
 create mode 100644 sys/include/arch/amd64/vas.h
 create mode 100644 sys/include/vm/pmap.h

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c
new file mode 100644
index 0000000..27bb44d
--- /dev/null
+++ b/sys/arch/amd64/amd64/pmap.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2023-2024 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/param.h>
+#include <sys/cdefs.h>
+#include <machine/tlb.h>
+#include <machine/vas.h>
+#include <vm/pmap.h>
+#include <vm/physmem.h>
+#include <vm/vm.h>
+#include <assert.h>
+#include <string.h>
+
+/*
+ * Page-Table Entry (PTE) flags
+ *
+ * See Intel SDM Vol 3A, Section 4.5, Table 4-19
+ */
+#define PTE_ADDR_MASK   0x000FFFFFFFFFF000
+#define PTE_P           BIT(0)        /* Present */
+#define PTE_RW          BIT(1)        /* Writable */
+#define PTE_US          BIT(2)        /* User r/w allowed */
+#define PTE_PWT         BIT(3)        /* Page-level write-through */
+#define PTE_PCD         BIT(4)        /* Page-level cache disable */
+#define PTE_ACC         BIT(5)        /* Accessed */
+#define PTE_DIRTY       BIT(6)        /* Dirty (written-to page) */
+#define PTE_PAT         BIT(7)
+#define PTE_GLOBAL      BIT(8)
+#define PTE_NX          BIT(63)       /* Execute-disable */
+
+/*
+ * Convert pmap protection flags to PTE flags.
+ */
+static uint64_t
+pmap_prot_to_pte(vm_prot_t prot)
+{
+    uint64_t pte_flags = PTE_P | PTE_NX;
+
+    if (ISSET(prot, PROT_WRITE))
+        pte_flags |= PTE_RW;
+    if (ISSET(prot, PROT_EXEC))
+        pte_flags &= ~(PTE_NX);
+    if (ISSET(prot, PROT_USER))
+        pte_flags |= PTE_US;
+
+    return pte_flags;
+}
+
+/*
+ * Returns index for a specific pagemap level.
+ *
+ * @level: Requested level.
+ * @va: Virtual address.
+ */
+static size_t
+pmap_get_level_index(uint8_t level, vaddr_t va)
+{
+    __assert(level <= 4 && level != 0);
+
+    switch (level) {
+    case 4:
+        return (va >> 39) & 0x1FF;
+    case 3:
+        return (va >> 30) & 0x1FF;
+    case 2:
+        return (va >> 21) & 0x1FF;
+    case 1:
+        return (va >> 12) & 0x1FF;
+    default:        /* Should not be reachable */
+        return 0;
+    }
+}
+
+/*
+ * Extract a pagemap level.
+ */
+static uintptr_t *
+pmap_extract(uint8_t level, vaddr_t va, vaddr_t *pmap, bool alloc)
+{
+    uintptr_t next, level_alloc;
+    size_t idx = pmap_get_level_index(level, va);
+
+    if (pmap == NULL) {
+        return NULL;
+    }
+
+    if (ISSET(pmap[idx], PTE_P)) {
+        next = (pmap[idx] & PTE_ADDR_MASK);
+        return PHYS_TO_VIRT(next);
+    }
+
+    if (!alloc) {
+        return 0;
+    }
+
+    /* Allocate the next level */
+    level_alloc = vm_alloc_frame(1);
+    if (level_alloc == 0)
+        return 0;
+
+    memset(PHYS_TO_VIRT(level_alloc), 0, DEFAULT_PAGESIZE);
+    pmap[idx] = level_alloc | (PTE_P | PTE_RW | PTE_US);
+    return PHYS_TO_VIRT(level_alloc);
+}
+
+/*
+ * Modify a page table by writing `val' to it.
+ *
+ * @vas: Virtual address space.
+ * @va: Virtual address.
+ * @alloc: True to alloc new entries.
+ * @res: Result
+ */
+static int
+pmap_get_tbl(struct vas vas, vaddr_t va, bool alloc, uintptr_t **res)
+{
+    uintptr_t *pml4 = PHYS_TO_VIRT(vas.top_level);
+    uintptr_t *pdpt, *pd, *tbl;
+    int status = 0;
+
+    pdpt = pmap_extract(4, va, pml4, alloc);
+    if (pdpt == NULL) {
+        status = 1;
+        goto done;
+    }
+
+    pd = pmap_extract(3, va, pdpt, alloc);
+    if (pd == NULL) {
+        status = 1;
+        goto done;
+    }
+
+    tbl = pmap_extract(2, va, pd, alloc);
+    if (tbl == NULL) {
+        status = 1;
+        goto done;
+    }
+
+    *res = tbl;
+done:
+    return status;
+}
+
+/*
+ * Update the value in a page table.
+ *
+ * @vas: Virtual address space.
+ * @va: Target virtual address.
+ * @val: Value to write.
+ */
+static int
+pmap_update_tbl(struct vas vas, vaddr_t va, uint64_t val)
+{
+    uintptr_t *tbl;
+    int status;
+
+    if ((status = pmap_get_tbl(vas, va, true, &tbl)) != 0) {
+        return status;
+    }
+
+    tbl[pmap_get_level_index(1, va)] = val;
+    tlb_flush(va);
+    return 0;
+}
+
+struct vas
+pmap_read_vas(void)
+{
+    struct vas vas;
+    uint64_t cr3_raw;
+
+    __ASMV("mov %%cr3, %0"
+           : "=r" (cr3_raw)
+           :
+           : "memory"
+    );
+
+    vas.cr3_flags = cr3_raw & ~PTE_ADDR_MASK;
+    vas.top_level = cr3_raw & PTE_ADDR_MASK;
+    vas.use_l5_paging = false;  /* TODO */
+    vas.lock.lock = 0;
+    return vas;
+}
+
+void
+pmap_switch_vas(struct vas vas)
+{
+    uintptr_t cr3_val = vas.cr3_flags | vas.top_level;
+
+    __ASMV("mov %0, %%cr3"
+           :
+           : "r" (cr3_val)
+           : "memory"
+    );
+}
+
+int
+pmap_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot)
+{
+    uint32_t flags = pmap_prot_to_pte(prot);
+
+    return pmap_update_tbl(vas, va, (pa | flags));
+}
+
+int
+pmap_unmap(struct vas vas, vaddr_t va)
+{
+    return pmap_update_tbl(vas, va, 0);
+}
diff --git a/sys/include/arch/amd64/tlb.h b/sys/include/arch/amd64/tlb.h
new file mode 100644
index 0000000..1e5dc40
--- /dev/null
+++ b/sys/include/arch/amd64/tlb.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_TLB_H_
+#define _MACHINE_TLB_H_
+
+#include <sys/cdefs.h>
+
+#define tlb_flush(va)           \
+    __ASMV("invlpg (%0)"        \
+           :                    \
+           : "r" (va)           \
+           : "memory"           \
+    )
+
+#endif  /* !_MACHINE_TLB_H_ */
diff --git a/sys/include/arch/amd64/vas.h b/sys/include/arch/amd64/vas.h
new file mode 100644
index 0000000..35f291f
--- /dev/null
+++ b/sys/include/arch/amd64/vas.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2023-2024 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 _MACHINE_VAS_H_
+#define _MACHINE_VAS_H_
+
+#include <sys/types.h>
+#include <sys/spinlock.h>
+
+/*
+ * VAS structure - describes a virtual address space
+ */
+struct vas {
+    size_t cr3_flags;       /* CR3 flags */
+    uintptr_t top_level;    /* PML5 if `use_l5_paging' true, otherwise PML4 */
+    bool use_l5_paging;     /* True if 5-level paging is supported */
+    struct spinlock lock;
+};
+
+#endif  /* !_MACHINE_VAS_H_ */
diff --git a/sys/include/vm/pmap.h b/sys/include/vm/pmap.h
new file mode 100644
index 0000000..ec669a8
--- /dev/null
+++ b/sys/include/vm/pmap.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2023-2024 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_PMAP_H_
+#define _VM_PMAP_H_
+
+#include <sys/types.h>
+#include <machine/vas.h>
+
+/* Protection flags for mappings */
+#define PROT_READ       0x00000000UL
+#define PROT_WRITE      BIT(0)      /* Writable */
+#define PROT_EXEC       BIT(1)      /* Executable */
+#define PROT_USER       BIT(2)      /* User accessible */
+
+typedef uint32_t vm_prot_t;
+
+/*
+ * Fetch the current address space.
+ */
+struct vas pmap_read_vas(void);
+
+/*
+ * Switch the virtual address space.
+ */
+void pmap_switch_vas(struct vas vas);
+
+/*
+ * Create a virtual memory mapping of a single page.
+ */
+int pmap_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot);
+
+/*
+ * Unmap a virtual memory mapping of a single page.
+ */
+int pmap_unmap(struct vas vas, vaddr_t va);
+
+#endif  /* !_VM_PMAP_H_ */
-- 
cgit v1.2.3


From 89faf05372902e19c0d15691022d4b0cf29ba2ef Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Thu, 13 Jun 2024 00:57:38 -0400
Subject: kernel/amd64: pmap: Fixup and improve consistency

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/pmap.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c
index 27bb44d..6047699 100644
--- a/sys/arch/amd64/amd64/pmap.c
+++ b/sys/arch/amd64/amd64/pmap.c
@@ -117,13 +117,14 @@ pmap_extract(uint8_t level, vaddr_t va, vaddr_t *pmap, bool alloc)
     }
 
     if (!alloc) {
-        return 0;
+        return NULL;
     }
 
     /* Allocate the next level */
     level_alloc = vm_alloc_frame(1);
-    if (level_alloc == 0)
-        return 0;
+    if (level_alloc == 0) {
+        return NULL;
+    }
 
     memset(PHYS_TO_VIRT(level_alloc), 0, DEFAULT_PAGESIZE);
     pmap[idx] = level_alloc | (PTE_P | PTE_RW | PTE_US);
-- 
cgit v1.2.3


From f290314f286b70a8f59becedd5f789c21f675b5d Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Thu, 20 Jun 2024 20:35:38 -0400
Subject: kernel/amd64: intr: Add splraise/splx support

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/intr.c   | 63 ++++++++++++++++++++++++++++++++++++++++---
 sys/arch/amd64/amd64/lapic.c  |  2 +-
 sys/include/arch/amd64/asm.h  | 14 ++++++++++
 sys/include/arch/amd64/cpu.h  |  1 +
 sys/include/arch/amd64/intr.h | 19 ++++++++++++-
 5 files changed, 93 insertions(+), 6 deletions(-)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c
index b841da7..3e3f309 100644
--- a/sys/arch/amd64/amd64/intr.c
+++ b/sys/arch/amd64/amd64/intr.c
@@ -28,16 +28,71 @@
  */
 
 #include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/panic.h>
 #include <machine/intr.h>
+#include <machine/cpu.h>
+#include <machine/asm.h>
+#include <vm/dynalloc.h>
+
+static struct intr_entry *intrs[256] = {0};
+
+void
+splraise(uint8_t s)
+{
+    struct cpu_info *ci = this_cpu();
+
+    if (s < ci->ipl) {
+        panic("splraise IPL less than current IPL\n");
+    }
+
+    amd64_write_cr8(s);
+    ci->ipl = s;
+}
+
+void
+splx(uint8_t s)
+{
+    struct cpu_info *ci = this_cpu();
+
+    if (s > ci->ipl) {
+        panic("splx IPL greater than current IPL\n");
+    }
+
+    amd64_write_cr8(s);
+    ci->ipl = s;
+}
 
 int
-intr_alloc_vector(void)
+intr_alloc_vector(const char *name, uint8_t priority)
 {
-    static size_t vec = 0x21;
+    size_t vec = MAX(priority << IPL_SHIFT, 0x20);
+    struct intr_entry *intr;
 
-    if (vec >= 0xFF) {
+    /* Sanity check */
+    if (vec > NELEM(intrs)) {
         return -1;
     }
 
-    return vec++;
+    /*
+     * Try to allocate an interrupt vector. An IPL is made up
+     * of 4 bits so there can be 16 vectors per IPL.
+     */
+    for (int i = vec; i < vec + 16; ++i) {
+        if (intrs[i] != NULL) {
+            continue;
+        }
+
+        intr = dynalloc(sizeof(*intr));
+        if (intr == NULL) {
+            return -ENOMEM;
+        }
+
+        intr->priority = priority;
+        intrs[i] = intr;
+        return i;
+    }
+
+    return -1;
 }
diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index b7cefd4..896c2bd 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -317,7 +317,7 @@ lapic_init(void)
 
     /* Allocate a vector if needed */
     if (lapic_timer_vec == 0) {
-        lapic_timer_vec = intr_alloc_vector();
+        lapic_timer_vec = intr_alloc_vector("lapictmr", IPL_CLOCK);
         idt_set_desc(lapic_timer_vec, IDT_INT_GATE, ISR(lapic_tmr_isr),
             IST_SCHED);
     }
diff --git a/sys/include/arch/amd64/asm.h b/sys/include/arch/amd64/asm.h
index d7334fe..e85dd87 100644
--- a/sys/include/arch/amd64/asm.h
+++ b/sys/include/arch/amd64/asm.h
@@ -84,6 +84,20 @@ amd64_write_cr0(uint64_t val)
     __ASMV("mov %0, %%cr0" :: "r" (val) : "memory");
 }
 
+static inline uint64_t
+amd64_read_cr8(void)
+{
+    uint64_t cr8;
+    __ASMV("mov %%cr8, %0" : "=r" (cr8) :: "memory");
+    return cr8;
+}
+
+static inline void
+amd64_write_cr8(uint64_t val)
+{
+    __ASMV("mov %0, %%cr8" :: "r" (val) : "memory");
+}
+
 static inline uint64_t
 amd64_read_cr4(void)
 {
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
index b5420a6..16936e9 100644
--- a/sys/include/arch/amd64/cpu.h
+++ b/sys/include/arch/amd64/cpu.h
@@ -38,6 +38,7 @@
 struct cpu_info {
     uint32_t apicid;
     uint8_t has_x2apic : 1;
+    uint8_t ipl;
     size_t lapic_tmr_freq;
     struct tss_entry *tss;
     struct proc *curtd;
diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h
index 3f0da77..af5edf2 100644
--- a/sys/include/arch/amd64/intr.h
+++ b/sys/include/arch/amd64/intr.h
@@ -36,6 +36,23 @@
 #define IST_HW_IRQ  2U
 #define IST_SW_INT  3U
 
-int intr_alloc_vector(void);
+/* Upper 4 bits of interrupt vector */
+#define IPL_SHIFT 4
+
+/*
+ * Interrupt priority levels
+ */
+#define IPL_NONE    0   /* Don't defer anything */
+#define IPL_BIO     1   /* Block I/O */
+#define IPL_CLOCK   2   /* Clock */
+#define IPL_HIGH    3   /* Defer everything */
+
+struct intr_entry {
+    int priority;
+};
+
+int intr_alloc_vector(const char *name, uint8_t priority);
+void splraise(uint8_t s);
+void splx(uint8_t s);
 
 #endif
-- 
cgit v1.2.3


From 347a1a0eeb5aa84e287e443a468a47a0fafd153f Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sun, 23 Jun 2024 19:01:29 -0400
Subject: kernel/amd64: pmap: Add function to create new VAS

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/pmap.c | 33 +++++++++++++++++++++++++++++++++
 sys/include/vm/pmap.h       |  5 +++++
 2 files changed, 38 insertions(+)

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c
index 6047699..108cd91 100644
--- a/sys/arch/amd64/amd64/pmap.c
+++ b/sys/arch/amd64/amd64/pmap.c
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/cdefs.h>
+#include <sys/errno.h>
 #include <machine/tlb.h>
 #include <machine/vas.h>
 #include <vm/pmap.h>
@@ -191,6 +192,38 @@ pmap_update_tbl(struct vas vas, vaddr_t va, uint64_t val)
     return 0;
 }
 
+int
+pmap_new_vas(struct vas *res)
+{
+    const struct vas *kvas = &g_kvas;
+    struct vas new_vas;
+    uint64_t *src, *dest;
+
+    new_vas.cr3_flags = kvas->cr3_flags;
+    new_vas.top_level = vm_alloc_frame(1);
+    if (new_vas.top_level == 0)
+        return -ENOMEM;
+
+    src = PHYS_TO_VIRT(kvas->top_level);
+    dest = PHYS_TO_VIRT(new_vas.top_level);
+
+    /*
+     * Keep the higher half but zero out the lower
+     * half for user programs.
+     */
+    for (int i = 0; i < 512; ++i) {
+        if (i < 256) {
+            dest[i] = 0;
+            continue;
+        }
+
+        dest[i] = src[i];
+    }
+
+    *res = new_vas;
+    return 0;
+}
+
 struct vas
 pmap_read_vas(void)
 {
diff --git a/sys/include/vm/pmap.h b/sys/include/vm/pmap.h
index ec669a8..dccfe0d 100644
--- a/sys/include/vm/pmap.h
+++ b/sys/include/vm/pmap.h
@@ -51,6 +51,11 @@ struct vas pmap_read_vas(void);
  */
 void pmap_switch_vas(struct vas vas);
 
+/*
+ * Create a new virtual address space.
+ */
+int pmap_new_vas(struct vas *res);
+
 /*
  * Create a virtual memory mapping of a single page.
  */
-- 
cgit v1.2.3


From 84f6abd193211b30c62a7c708edaccbe3ede8ee7 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sun, 23 Jun 2024 22:35:44 -0400
Subject: kernel/amd64: Add machdep thread init function

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/arch/amd64/amd64/proc_machdep.c | 107 ++++++++++++++++++++++++++++++++++++
 sys/include/sys/proc.h              |   3 +
 2 files changed, 110 insertions(+)
 create mode 100644 sys/arch/amd64/amd64/proc_machdep.c

(limited to 'sys/arch/amd64')

diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c
new file mode 100644
index 0000000..eb3866a
--- /dev/null
+++ b/sys/arch/amd64/amd64/proc_machdep.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2023-2024 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/proc.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <machine/frame.h>
+#include <machine/gdt.h>
+#include <vm/physmem.h>
+#include <vm/vm.h>
+#include <vm/map.h>
+#include <string.h>
+
+/*
+ * MD thread init code
+ *
+ * @p: New process.
+ * @parent: Parent of new process.
+ * @ip: Instruction pointer.
+ */
+int
+md_td_init(struct proc *p, struct proc *parent, uintptr_t ip)
+{
+    uintptr_t stack_base;
+    struct trapframe *tfp, *parent_tfp;
+    struct pcb *pcbp;
+    uint8_t rpl;
+    int error;
+
+    tfp = &p->tf;
+
+    /* Create a new VAS for this thread */
+    pcbp = &p->pcb;
+    if ((error = pmap_new_vas(&pcbp->addrsp)) != 0)
+        return error;
+
+    /*
+     * If parent is NULL, assume kernel space and zero the
+     * trapframe. Otherwise we can just set it up normally.
+     */
+    if (parent == NULL) {
+        rpl = 0;
+        memset(tfp, 0, sizeof(*tfp));
+    } else {
+        parent_tfp = &parent->tf;
+        rpl = parent_tfp->cs & 3;
+        memcpy(tfp, &parent->tf, sizeof(*tfp));
+    }
+
+    /*
+     * RPL being 3 indicates that the parent thread is in
+     * userland. If this is the case, we'd want this new thread
+     * to also be in userland.
+     */
+    tfp->rip = ip;
+    tfp->cs = (rpl == 3) ? (USER_CS | 3) : KERNEL_CS;
+    tfp->ss = (rpl == 3) ? (USER_DS | 3) : KERNEL_DS;
+    tfp->rflags = 0x202;
+
+    /* Try to allocate a new stack */
+    stack_base = vm_alloc_frame(PROC_STACK_PAGES);
+    if (stack_base == 0)
+        return -ENOMEM;
+
+    /*
+     * If RPL is 0 (kernel), adjust the stack base to the
+     * higher half. If we have an RPL of 3 (user) then we'll
+     * need to identity map the stack.
+     */
+    if (rpl == 0) {
+        stack_base += VM_HIGHER_HALF;
+    } else {
+        vm_map(pcbp->addrsp, stack_base, stack_base,
+            PROT_READ | PROT_WRITE | PROT_USER, PROC_STACK_PAGES);
+    }
+
+    p->stack_base = stack_base;
+    tfp->rsp = ALIGN_DOWN((stack_base + PROC_STACK_SIZE) - 1, 16);
+    return 0;
+}
diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h
index b74cb00..db41a4b 100644
--- a/sys/include/sys/proc.h
+++ b/sys/include/sys/proc.h
@@ -39,6 +39,8 @@
 #endif  /* _KERNEL */
 
 #if defined(_KERNEL)
+#define PROC_STACK_PAGES 8
+#define PROC_STACK_SIZE  (PROC_STACK_PAGES * DEFAULT_PAGESIZE)
 
 struct proc {
     pid_t pid;
@@ -50,6 +52,7 @@ struct proc {
 };
 
 struct proc *this_td(void);
+int md_td_init(struct proc *p, struct proc *parent, uintptr_t ip);
 
 #endif  /* _KERNEL */
 #endif  /* !_SYS_PROC_H_ */
-- 
cgit v1.2.3