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/include/arch/amd64/asm.h      | 113 ++++++++++++++++++++++++++++++++++++++
 sys/include/arch/amd64/cpu.h      |  43 +++++++++++++++
 sys/include/arch/amd64/cpuid.h    |  40 ++++++++++++++
 sys/include/arch/amd64/frame.h    |  61 ++++++++++++++++++++
 sys/include/arch/amd64/frameasm.h | 103 ++++++++++++++++++++++++++++++++++
 sys/include/arch/amd64/gdt.h      |  47 ++++++++++++++++
 sys/include/arch/amd64/idt.h      |  68 +++++++++++++++++++++++
 sys/include/arch/amd64/msr.h      |  63 +++++++++++++++++++++
 sys/include/arch/amd64/pio.h      |  43 +++++++++++++++
 sys/include/arch/amd64/trap.h     |  68 +++++++++++++++++++++++
 10 files changed, 649 insertions(+)
 create mode 100644 sys/include/arch/amd64/asm.h
 create mode 100644 sys/include/arch/amd64/cpu.h
 create mode 100644 sys/include/arch/amd64/cpuid.h
 create mode 100644 sys/include/arch/amd64/frame.h
 create mode 100644 sys/include/arch/amd64/frameasm.h
 create mode 100644 sys/include/arch/amd64/gdt.h
 create mode 100644 sys/include/arch/amd64/idt.h
 create mode 100644 sys/include/arch/amd64/msr.h
 create mode 100644 sys/include/arch/amd64/pio.h
 create mode 100644 sys/include/arch/amd64/trap.h

(limited to 'sys/include/arch/amd64')

diff --git a/sys/include/arch/amd64/asm.h b/sys/include/arch/amd64/asm.h
new file mode 100644
index 0000000..d7334fe
--- /dev/null
+++ b/sys/include/arch/amd64/asm.h
@@ -0,0 +1,113 @@
+/*
+ * 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_ASM_H_
+#define _MACHINE_ASM_H_
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <machine/msr.h>
+
+/*
+ * Contains information for the current
+ * core. Stored in %GS.
+ *
+ * MUST REMAIN IN ORDER!!!
+ */
+struct cpu_ctx {
+    struct cpu_info *ci;
+};
+
+/*
+ * Returns true for this core if maskable
+ * interrupts are masked (CLI) and false if
+ * they aren't (STI).
+ */
+static inline bool
+amd64_is_intr_mask(void)
+{
+    uint64_t flags;
+
+    __ASMV("pushfq; pop %0" : "=rm" (flags) :: "memory");
+    return !ISSET(flags, BIT(9));
+}
+
+static inline void
+amd64_write_gs_base(uintptr_t val)
+{
+    wrmsr(IA32_KERNEL_GS_BASE, val);
+}
+
+static inline uintptr_t
+amd64_read_gs_base(void)
+{
+    return rdmsr(IA32_KERNEL_GS_BASE);
+}
+
+static inline uint64_t
+amd64_read_cr0(void)
+{
+    uint64_t cr0;
+    __ASMV("mov %%cr0, %0" : "=r" (cr0) :: "memory");
+    return cr0;
+}
+
+static inline void
+amd64_write_cr0(uint64_t val)
+{
+    __ASMV("mov %0, %%cr0" :: "r" (val) : "memory");
+}
+
+static inline uint64_t
+amd64_read_cr4(void)
+{
+    uint64_t cr4;
+    __ASMV("mov %%cr4, %0" : "=r" (cr4) :: "memory");
+    return cr4;
+}
+
+static inline void
+amd64_write_cr4(uint64_t val)
+{
+    __ASMV("mov %0, %%cr4" :: "r" (val) : "memory");
+}
+
+static inline void
+amd64_fxsave(void *area)
+{
+    __ASMV("fxsave (%0)" :: "r" (area) : "memory");
+}
+
+static inline void
+amd64_fxrstor(void *area)
+{
+    __ASMV("fxrstor (%0)" :: "r" (area) : "memory");
+}
+
+#endif
diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h
new file mode 100644
index 0000000..efa60ad
--- /dev/null
+++ b/sys/include/arch/amd64/cpu.h
@@ -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.
+ */
+
+#ifndef _MACHINE_CPU_H_
+#define _MACHINE_CPU_H_
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+struct cpu_info {
+    uint32_t apicid;
+};
+
+void cpu_startup(void);
+
+
+#endif  /* !_MACHINE_CPU_H_ */
diff --git a/sys/include/arch/amd64/cpuid.h b/sys/include/arch/amd64/cpuid.h
new file mode 100644
index 0000000..d1a752b
--- /dev/null
+++ b/sys/include/arch/amd64/cpuid.h
@@ -0,0 +1,40 @@
+/*
+ * 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_CPUID_H_
+#define _MACHINE_CPUID_H_
+
+#include <sys/cdefs.h>
+
+#define CPUID(level, a, b, c, d)                        \
+    __ASMV("cpuid\n\t"                                  \
+            : "=a" (a), "=b" (b), "=c" (c), "=d" (d)    \
+            : "0" (level))
+
+#endif  /* !_MACHINE_CPUID_H_ */
diff --git a/sys/include/arch/amd64/frame.h b/sys/include/arch/amd64/frame.h
new file mode 100644
index 0000000..a132e4c
--- /dev/null
+++ b/sys/include/arch/amd64/frame.h
@@ -0,0 +1,61 @@
+/*
+ * 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_FRAME_H_
+#define _MACHINE_FRAME_H_
+
+#include <sys/types.h>
+
+struct trapframe {
+    uint64_t trapno;
+    uint64_t rax;
+    uint64_t rcx;
+    uint64_t rdx;
+    uint64_t rbx;
+    uint64_t rsi;
+    uint64_t rdi;
+    uint64_t rbp;
+    uint64_t r8;
+    uint64_t r9;
+    uint64_t r10;
+    uint64_t r11;
+    uint64_t r12;
+    uint64_t r13;
+    uint64_t r14;
+    uint64_t r15;
+    /* Pushed by hardware */
+    uint64_t error_code;
+    uint64_t rip;
+    uint64_t cs;
+    uint64_t rflags;
+    uint64_t rsp;
+    uint64_t ss;
+};
+
+#endif  /* !_MACHINE_FRAME_H_ */
diff --git a/sys/include/arch/amd64/frameasm.h b/sys/include/arch/amd64/frameasm.h
new file mode 100644
index 0000000..b6d4f39
--- /dev/null
+++ b/sys/include/arch/amd64/frameasm.h
@@ -0,0 +1,103 @@
+/*
+ * 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_FRAMEASM_H_
+#define _MACHINE_FRAMEASM_H_
+
+/*
+ * If the interrupt has an error code, this macro shall
+ * be used to create the trapframe.
+ *
+ * XXX: A trapframe created with this must be popped with
+ *      pop_trapframe_ec
+ */
+.macro push_trapframe_ec trapno
+    push %r15
+    push %r14
+    push %r13
+    push %r12
+    push %r11
+    push %r10
+    push %r9
+    push %r8
+    push %rbp
+    push %rdi
+    push %rsi
+    push %rbx
+    push %rdx
+    push %rcx
+    push %rax
+    push \trapno
+.endm
+
+/*
+ * If the interrupt has an error code, this macro shall
+ * be used to cleanup the trapframe.
+ */
+.macro pop_trapframe_ec
+    add $8, %rsp        /* Trapno */
+    pop %rax
+    pop %rcx
+    pop %rdx
+    pop %rbx
+    pop %rsi
+    pop %rdi
+    pop %rbp
+    pop %r8
+    pop %r9
+    pop %r10
+    pop %r11
+    pop %r12
+    pop %r13
+    pop %r14
+    pop %r15
+.endm
+
+/*
+ * If the interrupt has no error code, this macro
+ * shall be used to create the trapframe.
+ *
+ * XXX: A trapframe created with this must be popped
+ *      with pop_trapframe
+ */
+.macro push_trapframe trapno
+    push $0
+    push_trapframe_ec \trapno
+.endm
+
+
+/*
+ * If the interrupt has no error code, this macro shall
+ * be used to cleanup the trapframe.
+ */
+.macro pop_trapframe
+    pop_trapframe_ec
+    add $8, %rsp        /* Pop error code */
+.endm
+#endif  /* !_MACHINE_FRAMEASM_H_ */
diff --git a/sys/include/arch/amd64/gdt.h b/sys/include/arch/amd64/gdt.h
new file mode 100644
index 0000000..6f8a914
--- /dev/null
+++ b/sys/include/arch/amd64/gdt.h
@@ -0,0 +1,47 @@
+#ifndef _AMD64_GDT_H_
+#define _AMD64_GDT_H_
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+#define KERNEL_CS 0x08
+#define KERNEL_DS 0x10
+
+struct __packed gdt_entry {
+    uint16_t limit;
+    uint16_t base_low;
+    uint8_t base_mid;
+    uint8_t access;
+    uint8_t granularity;
+    uint8_t base_hi;
+};
+
+struct __packed gdtr {
+    uint16_t limit;
+    uintptr_t offset;
+};
+
+__always_inline static inline void
+gdt_load(struct gdtr *gdtr)
+{
+        __ASMV("lgdt %0\n"
+               "push $8\n"               /* Push CS */
+               "lea 1f(%%rip), %%rax\n"  /* Load 1 label address into RAX */
+               "push %%rax\n"            /* Push the return address (label 1) */
+               "lretq\n"                 /* Far return to update CS */
+               "1:\n"
+               "  mov $0x10, %%eax\n"
+               "  mov %%eax, %%ds\n"
+               "  mov %%eax, %%es\n"
+               "  mov %%eax, %%fs\n"
+               "  mov %%eax, %%gs\n"
+               "  mov %%eax, %%ss\n"
+               :
+               : "m" (*gdtr)
+               : "rax", "memory"
+        );
+}
+
+extern struct gdt_entry g_gdt_data[256];
+
+#endif  /* !AMD64_GDT_H_ */
diff --git a/sys/include/arch/amd64/idt.h b/sys/include/arch/amd64/idt.h
new file mode 100644
index 0000000..7f439f3
--- /dev/null
+++ b/sys/include/arch/amd64/idt.h
@@ -0,0 +1,68 @@
+/*
+ * 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_IDT_H_
+#define _MACHINE_IDT_H_
+
+#include <sys/types.h>
+#include <sys/cdefs.h>
+
+#define IDT_TRAP_GATE       0x8F
+#define IDT_INT_GATE        0x8E
+#define IDT_USER_INT_GATE   0xEE
+
+#define ISR(p) ((uintptr_t)p)
+
+/*
+ * AMD64 Interrupt Gate Descriptor.
+ */
+struct idt_entry {
+    uint16_t    off_lo;         /* Low 16 bits of ISR offset */
+    uint16_t    segsel;         /* Segment selector, hardcode to kernel CS */
+    uint8_t     ist    : 2;     /* Interrupt stack table */
+    uint8_t     zero   : 1;     /* Unused: keep zero */
+    uint8_t     zero1  : 4;     /* Unused: keep zero */
+    uint8_t     type   : 4;     /* Gate type */
+    uint8_t     zero2  : 1;     /* Unused: keep zero */
+    uint8_t     dpl    : 2;     /* Descriptor privilege level */
+    uint8_t     p      : 1;     /* Present (keep 1 to mark as valid) */
+    uint16_t    off_mid;        /* Middle 16 bits of ISR offset */
+    uint32_t    off_hi;         /* High 32-bits of ISR offset */
+    uint32_t    reserved;       /* Reserved: keep zero */
+};
+
+struct __packed idtr {
+    uint16_t limit;
+    uintptr_t offset;
+};
+
+void idt_set_desc(uint8_t vector, uint8_t type, uintptr_t isr, uint8_t ist);
+void idt_load(void);
+
+#endif  /* !_MACHINE_IDT_H_ */
diff --git a/sys/include/arch/amd64/msr.h b/sys/include/arch/amd64/msr.h
new file mode 100644
index 0000000..bc0dbcb
--- /dev/null
+++ b/sys/include/arch/amd64/msr.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 _MACHINE_MSR_H_
+#define _MACHINE_MSR_H_
+
+#define IA32_SPEC_CTL       0x00000048
+#define IA32_KERNEL_GS_BASE 0xC0000102
+
+static inline uint64_t
+rdmsr(uint32_t msr_addr)
+{
+    uint32_t lo, hi;
+
+    __ASMV("rdmsr"
+           : "=a" (lo), "=d" (hi)
+           : "c" (msr_addr)
+    );
+    return ((uint64_t)hi << 32) | lo;
+}
+
+static inline void
+wrmsr(uint32_t msr_addr, uint64_t value)
+{
+    uint32_t lo, hi;
+
+    lo = (uint32_t)value;
+    hi = (uint32_t)(value >> 32);
+
+    __ASMV("wrmsr"
+           :  /* No outputs */
+           : "a" (lo), "d" (hi),
+             "c" (msr_addr)
+    );
+}
+
+#endif  /* !_MACHINE_MSR_H_ */
diff --git a/sys/include/arch/amd64/pio.h b/sys/include/arch/amd64/pio.h
new file mode 100644
index 0000000..193e986
--- /dev/null
+++ b/sys/include/arch/amd64/pio.h
@@ -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.
+ */
+
+#ifndef _MACHINE_PIO_H_
+#define _MACHINE_PIO_H_
+
+#include <sys/types.h>
+
+uint8_t inb(uint16_t port);
+uint16_t inw(uint16_t port);
+uint32_t inl(uint16_t port);
+
+void outb(uint16_t port, uint8_t val);
+void outw(uint16_t port, uint16_t val);
+void outl(uint16_t port, uint32_t val);
+
+#endif  /* !_MACHINE_PIO_H_ */
diff --git a/sys/include/arch/amd64/trap.h b/sys/include/arch/amd64/trap.h
new file mode 100644
index 0000000..deeb738
--- /dev/null
+++ b/sys/include/arch/amd64/trap.h
@@ -0,0 +1,68 @@
+/*
+ * 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_TRAP_H_
+#define _MACHINE_TRAP_H_
+
+#if !defined(__ASSEMBLER__)
+#include <machine/frame.h>
+#endif
+
+#define TRAP_NONE           0       /* Used for general interrupts */
+#define TRAP_BREAKPOINT     1       /* Breakpoint */
+#define TRAP_ARITH_ERR      2       /* Arithmetic error (e.g division by 0) */
+#define TRAP_OVERFLOW       3       /* Overflow */
+#define TRAP_BOUND_RANGE    4       /* BOUND range exceeded */
+#define TRAP_INVLOP         5       /* Invalid opcode */
+#define TRAP_DOUBLE_FAULT   6       /* Double fault */
+#define TRAP_INVLTSS        7       /* Invalid TSS */
+#define TRAP_SEGNP          8       /* Segment not present */
+#define TRAP_PROTFLT        9       /* General protection */
+#define TRAP_PAGEFLT        10      /* Page fault */
+#define TRAP_NMI            11      /* Non-maskable interrupt */
+#define TRAP_SS             12      /* Stack-segment fault */
+
+#if !defined(__ASSEMBLER__)
+
+void breakpoint_handler(void *sf);
+void arith_err(void *sf);
+void overflow(void *sf);
+void bound_range(void *sf);
+void invl_op(void *sf);
+void double_fault(void *sf);
+void invl_tss(void *sf);
+void segnp(void *sf);
+void general_prot(void *sf);
+void page_fault(void *sf);
+void nmi(void *sf);
+void ss_fault(void *sf);
+void trap_handler(struct trapframe *tf);
+
+#endif  /* !__ASSEMBLER__ */
+#endif  /* !_MACHINE_TRAP_H_ */
-- 
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/include/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 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/include/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 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/include/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 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/include/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/include/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/include/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/include/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/include/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 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/include/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/include/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/include/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/include/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 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/include/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 aa8d940e7e1cadf651054a58d6953fee03149587 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sun, 23 Jun 2024 22:23:53 -0400
Subject: kernel/amd64: gdt: Add user CS/DS defines

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

(limited to 'sys/include/arch/amd64')

diff --git a/sys/include/arch/amd64/gdt.h b/sys/include/arch/amd64/gdt.h
index ce7dd60..f87416f 100644
--- a/sys/include/arch/amd64/gdt.h
+++ b/sys/include/arch/amd64/gdt.h
@@ -6,6 +6,8 @@
 
 #define KERNEL_CS 0x08
 #define KERNEL_DS 0x10
+#define USER_CS 0x18
+#define USER_DS 0x20
 #define GDT_TSS 5
 
 struct __packed gdt_entry {
-- 
cgit v1.2.3


From 00245135a7df4028df60f62f4041c1302e5b3381 Mon Sep 17 00:00:00 2001
From: Ian Moffett <ian@osmora.org>
Date: Sun, 23 Jun 2024 22:25:13 -0400
Subject: kernel: sched: Add PCB and context switching

Signed-off-by: Ian Moffett <ian@osmora.org>
---
 sys/include/arch/amd64/pcb.h | 40 +++++++++++++++++++++
 sys/include/sys/proc.h       | 11 ++++--
 sys/include/sys/sched.h      |  3 ++
 sys/kern/kern_sched.c        | 83 ++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 132 insertions(+), 5 deletions(-)
 create mode 100644 sys/include/arch/amd64/pcb.h

(limited to 'sys/include/arch/amd64')

diff --git a/sys/include/arch/amd64/pcb.h b/sys/include/arch/amd64/pcb.h
new file mode 100644
index 0000000..5d06ade
--- /dev/null
+++ b/sys/include/arch/amd64/pcb.h
@@ -0,0 +1,40 @@
+/*
+ * 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_PCB_H_
+#define _MACHINE_PCB_H_
+
+#include <sys/types.h>
+#include <vm/pmap.h>
+
+struct pcb {
+    struct vas addrsp;
+};
+
+#endif  /* !_MACHINE_PCB_H_ */
diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h
index ba47a5c..b74cb00 100644
--- a/sys/include/sys/proc.h
+++ b/sys/include/sys/proc.h
@@ -32,17 +32,24 @@
 
 #include <sys/types.h>
 #include <sys/spinlock.h>
+#include <sys/queue.h>
 #if defined(_KERNEL)
-#include <machine/cpu.h>
 #include <machine/frame.h>
+#include <machine/pcb.h>
 #endif  /* _KERNEL */
 
 #if defined(_KERNEL)
 
 struct proc {
     pid_t pid;
-    struct cpu_info *cpu;
+    struct trapframe tf;
+    struct pcb pcb;
+    size_t priority;
+    uintptr_t stack_base;
+    TAILQ_ENTRY(proc) link;
 };
 
+struct proc *this_td(void);
+
 #endif  /* _KERNEL */
 #endif  /* !_SYS_PROC_H_ */
diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h
index 33d546d..ae59d5f 100644
--- a/sys/include/sys/sched.h
+++ b/sys/include/sys/sched.h
@@ -30,10 +30,13 @@
 #ifndef _SYS_SCHED_H_
 #define _SYS_SCHED_H_
 
+#include <sys/proc.h>
+
 #if defined(_KERNEL)
 
 void sched_init(void);
 void sched_enter(void);
+void sched_enqueue_td(struct proc *td);
 
 #endif  /* _KERNEL */
 #endif  /* !_SYS_SCHED_H_ */
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
index b79d682..c370311 100644
--- a/sys/kern/kern_sched.c
+++ b/sys/kern/kern_sched.c
@@ -33,8 +33,11 @@
 #include <sys/cdefs.h>
 #include <sys/syslog.h>
 #include <machine/frame.h>
+#include <machine/cpu.h>
+#include <vm/pmap.h>
 #include <dev/timer.h>
 #include <assert.h>
+#include <string.h>
 
 #define pr_trace(fmt, ...) kprintf("ksched: " fmt, ##__VA_ARGS__)
 
@@ -48,6 +51,12 @@ static sched_policy_t policy = SCHED_POLICY_RR;
  */
 static struct sched_queue qlist[SCHED_NQUEUE];
 
+/*
+ * Thread queue lock - all operations to `qlist'
+ * must be done with this lock acquired.
+ */
+__cacheline_aligned static struct spinlock tdq_lock = {0};
+
 /*
  * Perform timer oneshot
  */
@@ -64,6 +73,54 @@ sched_oneshot(bool now)
     timer.oneshot_us(usec);
 }
 
+static struct proc *
+sched_dequeue_td(void)
+{
+    struct sched_queue *queue;
+    struct proc *td = NULL;
+
+    spinlock_acquire(&tdq_lock);
+
+    for (size_t i = 0; i < SCHED_NQUEUE; ++i) {
+        queue = &qlist[i];
+        if (!TAILQ_EMPTY(&queue->q)) {
+            td = TAILQ_FIRST(&queue->q);
+            TAILQ_REMOVE(&queue->q, td, link);
+            break;
+        }
+    }
+
+    spinlock_release(&tdq_lock);
+    return td;
+}
+
+/*
+ * Add a thread to the scheduler.
+ */
+void
+sched_enqueue_td(struct proc *td)
+{
+    struct sched_queue *queue;
+
+    spinlock_acquire(&tdq_lock);
+    queue = &qlist[td->priority];
+
+    TAILQ_INSERT_TAIL(&queue->q, td, link);
+    spinlock_release(&tdq_lock);
+}
+
+/*
+ * Return the currently running thread.
+ */
+struct proc *
+this_td(void)
+{
+    struct cpu_info *ci;
+
+    ci = this_cpu();
+    return ci->curtd;
+}
+
 /*
  * Perform a context switch.
  *
@@ -72,10 +129,30 @@ sched_oneshot(bool now)
 void
 sched_switch(struct trapframe *tf)
 {
-    static struct spinlock lock = {0};
+    struct cpu_info *ci;
+    struct pcb *pcbp;
+    struct proc *next_td, *td;
+
+    ci = this_cpu();
+    td = ci->curtd;
+
+    /* Do we have threads to switch to? */
+    if ((next_td = sched_dequeue_td()) == NULL) {
+        sched_oneshot(false);
+        return;
+    }
+
+    /* Re-enqueue the old thread */
+    if (td != NULL) {
+        memcpy(&td->tf, tf, sizeof(td->tf));
+        sched_enqueue_td(td);
+    }
+
+    memcpy(tf, &next_td->tf, sizeof(*tf));
+    ci->curtd = next_td;
+    pcbp = &next_td->pcb;
 
-    spinlock_acquire(&lock);
-    spinlock_release(&lock);
+    pmap_switch_vas(pcbp->addrsp);
     sched_oneshot(false);
 }
 
-- 
cgit v1.2.3