aboutsummaryrefslogtreecommitdiff
path: root/kernel/include/main
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/include/main')
-rw-r--r--kernel/include/main/acpi.h20
-rw-r--r--kernel/include/main/apic.h73
-rw-r--r--kernel/include/main/cpuid.h118
-rw-r--r--kernel/include/main/entry.h3
-rw-r--r--kernel/include/main/gdt.h21
-rw-r--r--kernel/include/main/inits.h15
-rw-r--r--kernel/include/main/interrupt.h117
-rw-r--r--kernel/include/main/io.h46
-rw-r--r--kernel/include/main/smp.h22
9 files changed, 435 insertions, 0 deletions
diff --git a/kernel/include/main/acpi.h b/kernel/include/main/acpi.h
new file mode 100644
index 0000000..dc49805
--- /dev/null
+++ b/kernel/include/main/acpi.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <types.h>
+
+typedef struct acpi_header
+{
+ uint32_t ah_sign;
+ uint32_t ah_size;
+ uint8_t ah_rev;
+ uint8_t ah_checksum;
+ uint8_t ah_oemid[6];
+ uint8_t ah_tableid[8];
+ uint32_t ah_oemrev;
+ uint32_t ah_creatorid;
+ uint32_t ah_creatorrev;
+} packed acpi_header_t;
+
+void acpi_init();
+
+void *acpi_table(uint32_t signature, int index);
diff --git a/kernel/include/main/apic.h b/kernel/include/main/apic.h
new file mode 100644
index 0000000..ca9c8f5
--- /dev/null
+++ b/kernel/include/main/apic.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "main/interrupt.h"
+#include "types.h"
+
+typedef enum
+{
+ DESTINATION_MODE_FIXED = 0,
+ DESTINATION_MODE_LOWEST_PRIORITY = 1,
+ DESTINATION_MODE_SMI = 2,
+ DESTINATION_MODE_NMI = 4,
+ DESTINATION_MODE_INIT = 5,
+ DESTINATION_MODE_SIPI = 6
+} ipi_destination_mode;
+
+#define MAX_LAPICS 8
+
+/* Initializes the APIC using data from the ACPI tables.
+ * ACPI handlers must be initialized before calling this
+ * function. */
+void apic_init();
+
+/* Returns the APIC ID of the current processor */
+long apic_current_id();
+
+/* Returns the largest known APIC ID */
+long apic_max_id();
+
+/* Maps the given IRQ to the given interrupt number. */
+void apic_setredir(uint32_t irq, uint8_t intr);
+
+void apic_enable();
+
+// timer interrupts arrive at a rate of (freq / 16) interrupts per millisecond
+// (with an )
+/* Starts the APIC timer */
+void apic_enable_periodic_timer(uint32_t freq);
+
+/* Stops the APIC timer */
+void apic_disable_periodic_timer();
+
+/* Sets the interrupt to raise when a spurious
+ * interrupt occurs. */
+void apic_setspur(uint8_t intr);
+
+/* Sets the interrupt priority level. This function should
+ * be accessed via wrappers in the interrupt subsystem. */
+void apic_setipl(uint8_t ipl);
+
+/* Gets the interrupt priority level. This function should
+ * be accessed via wrappers in the interrupt subsystem. */
+uint8_t apic_getipl();
+
+long apic_initialized();
+
+/* Writes to the APIC's memory mapped end-of-interrupt
+ * register to indicate that the handling of an interrupt
+ * originating from the APIC has been finished. This function
+ * should only be called from the interrupt subsystem. */
+void apic_eoi();
+
+void apic_start_processor(uint8_t target, uint8_t execution_page);
+
+void apic_send_ipi(uint8_t target, ipi_destination_mode destination_mode,
+ uint8_t vector);
+
+void apic_broadcast_ipi(ipi_destination_mode mode, uint8_t vector,
+ long include_self);
+
+/**
+ * Wait for the last IPI sent to be acknowledged by the target processor.
+ */
+void apic_wait_ipi(); \ No newline at end of file
diff --git a/kernel/include/main/cpuid.h b/kernel/include/main/cpuid.h
new file mode 100644
index 0000000..5d4b5fa
--- /dev/null
+++ b/kernel/include/main/cpuid.h
@@ -0,0 +1,118 @@
+#pragma once
+
+#include <types.h>
+
+/* Vendor-strings. */
+#define CPUID_VENDOR_AMD "AuthenticAMD"
+#define CPUID_VENDOR_INTEL "GenuineIntel"
+#define CPUID_VENDOR_VIA "CentaurHauls"
+#define CPUID_VENDOR_OLDTRANSMETA "TransmetaCPU"
+#define CPUID_VENDOR_TRANSMETA "GenuineTMx86"
+#define CPUID_VENDOR_CYRIX "CyrixInstead"
+#define CPUID_VENDOR_CENTAUR "CentaurHauls"
+#define CPUID_VENDOR_NEXGEN "NexGenDriven"
+#define CPUID_VENDOR_UMC "UMC UMC UMC "
+#define CPUID_VENDOR_SIS "SiS SiS SiS "
+#define CPUID_VENDOR_NSC "Geode by NSC"
+#define CPUID_VENDOR_RISE "RiseRiseRise"
+
+enum
+{
+ CPUID_FEAT_ECX_SSE3 = 1 << 0,
+ CPUID_FEAT_ECX_PCLMUL = 1 << 1,
+ CPUID_FEAT_ECX_DTES64 = 1 << 2,
+ CPUID_FEAT_ECX_MONITOR = 1 << 3,
+ CPUID_FEAT_ECX_DS_CPL = 1 << 4,
+ CPUID_FEAT_ECX_VMX = 1 << 5,
+ CPUID_FEAT_ECX_SMX = 1 << 6,
+ CPUID_FEAT_ECX_EST = 1 << 7,
+ CPUID_FEAT_ECX_TM2 = 1 << 8,
+ CPUID_FEAT_ECX_SSSE3 = 1 << 9,
+ CPUID_FEAT_ECX_CID = 1 << 10,
+ CPUID_FEAT_ECX_FMA = 1 << 12,
+ CPUID_FEAT_ECX_CX16 = 1 << 13,
+ CPUID_FEAT_ECX_ETPRD = 1 << 14,
+ CPUID_FEAT_ECX_PDCM = 1 << 15,
+ CPUID_FEAT_ECX_DCA = 1 << 18,
+ CPUID_FEAT_ECX_SSE4_1 = 1 << 19,
+ CPUID_FEAT_ECX_SSE4_2 = 1 << 20,
+ CPUID_FEAT_ECX_x2APIC = 1 << 21,
+ CPUID_FEAT_ECX_MOVBE = 1 << 22,
+ CPUID_FEAT_ECX_POPCNT = 1 << 23,
+ CPUID_FEAT_ECX_XSAVE = 1 << 26,
+ CPUID_FEAT_ECX_OSXSAVE = 1 << 27,
+ CPUID_FEAT_ECX_AVX = 1 << 28,
+
+ CPUID_FEAT_EDX_FPU = 1 << 0,
+ CPUID_FEAT_EDX_VME = 1 << 1,
+ CPUID_FEAT_EDX_DE = 1 << 2,
+ CPUID_FEAT_EDX_PSE = 1 << 3,
+ CPUID_FEAT_EDX_TSC = 1 << 4,
+ CPUID_FEAT_EDX_MSR = 1 << 5,
+ CPUID_FEAT_EDX_PAE = 1 << 6,
+ CPUID_FEAT_EDX_MCE = 1 << 7,
+ CPUID_FEAT_EDX_CX8 = 1 << 8,
+ CPUID_FEAT_EDX_APIC = 1 << 9,
+ CPUID_FEAT_EDX_SEP = 1 << 11,
+ CPUID_FEAT_EDX_MTRR = 1 << 12,
+ CPUID_FEAT_EDX_PGE = 1 << 13,
+ CPUID_FEAT_EDX_MCA = 1 << 14,
+ CPUID_FEAT_EDX_CMOV = 1 << 15,
+ CPUID_FEAT_EDX_PAT = 1 << 16,
+ CPUID_FEAT_EDX_PSE36 = 1 << 17,
+ CPUID_FEAT_EDX_PSN = 1 << 18,
+ CPUID_FEAT_EDX_CLF = 1 << 19,
+ CPUID_FEAT_EDX_DTES = 1 << 21,
+ CPUID_FEAT_EDX_ACPI = 1 << 22,
+ CPUID_FEAT_EDX_MMX = 1 << 23,
+ CPUID_FEAT_EDX_FXSR = 1 << 24,
+ CPUID_FEAT_EDX_SSE = 1 << 25,
+ CPUID_FEAT_EDX_SSE2 = 1 << 26,
+ CPUID_FEAT_EDX_SS = 1 << 27,
+ CPUID_FEAT_EDX_HTT = 1 << 28,
+ CPUID_FEAT_EDX_TM1 = 1 << 29,
+ CPUID_FEAT_EDX_IA64 = 1 << 30,
+ CPUID_FEAT_EDX_PBE = 1 << 31
+};
+
+enum cpuid_requests
+{
+ CPUID_GETVENDORSTRING,
+ CPUID_GETFEATURES,
+ CPUID_GETTLB,
+ CPUID_GETSERIAL,
+
+ CPUID_INTELEXTENDED = 0x80000000,
+ CPUID_INTELFEATURES,
+ CPUID_INTELBRANDSTRING,
+ CPUID_INTELBRANDSTRINGMORE,
+ CPUID_INTELBRANDSTRINGEND,
+};
+
+static inline void cpuid(int request, uint32_t *a, uint32_t *b, uint32_t *c,
+ uint32_t *d)
+{
+ __asm__ volatile("cpuid"
+ : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
+ : "0"(request));
+}
+
+static inline void cpuid_get_msr(uint32_t msr, uint32_t *lo, uint32_t *hi)
+{
+ __asm__ volatile("rdmsr"
+ : "=a"(*lo), "=d"(*hi)
+ : "c"(msr));
+}
+
+static inline void cpuid_set_msr(uint32_t msr, uint32_t lo, uint32_t hi)
+{
+ __asm__ volatile("wrmsr" ::"a"(lo), "d"(hi), "c"(msr));
+}
+
+static inline void io_wait(void)
+{
+ __asm__ volatile(
+ "jmp 1f\n\t"
+ "1:jmp 2f\n\t"
+ "2:");
+}
diff --git a/kernel/include/main/entry.h b/kernel/include/main/entry.h
new file mode 100644
index 0000000..64c0e96
--- /dev/null
+++ b/kernel/include/main/entry.h
@@ -0,0 +1,3 @@
+/* entry.h */
+
+void kmain(void);
diff --git a/kernel/include/main/gdt.h b/kernel/include/main/gdt.h
new file mode 100644
index 0000000..a991cbf
--- /dev/null
+++ b/kernel/include/main/gdt.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "types.h"
+
+#define GDT_COUNT 16
+
+#define GDT_ZERO 0x00
+#define GDT_KERNEL_TEXT 0x08
+#define GDT_KERNEL_DATA 0x10
+#define GDT_USER_TEXT 0x18
+#define GDT_USER_DATA 0x20
+#define GDT_TSS 0x28
+
+void gdt_init(void);
+
+void gdt_set_kernel_stack(void *addr);
+
+void gdt_set_entry(uint32_t segment, uint32_t base, uint32_t limit,
+ uint8_t ring, int exec, int dir, int rw);
+
+void gdt_clear(uint32_t segment); \ No newline at end of file
diff --git a/kernel/include/main/inits.h b/kernel/include/main/inits.h
new file mode 100644
index 0000000..5013b07
--- /dev/null
+++ b/kernel/include/main/inits.h
@@ -0,0 +1,15 @@
+#pragma once
+
+extern void sched_init();
+
+extern void kshell_init();
+
+extern void file_init();
+
+extern void pipe_init();
+
+extern void vfs_init();
+
+extern void syscall_init();
+
+extern void elf64_init(void);
diff --git a/kernel/include/main/interrupt.h b/kernel/include/main/interrupt.h
new file mode 100644
index 0000000..6a9ae00
--- /dev/null
+++ b/kernel/include/main/interrupt.h
@@ -0,0 +1,117 @@
+#pragma once
+
+#include "kernel.h"
+#include "types.h"
+#include "util/debug.h"
+
+// intr_disk_priamry/seconday so that they are different task priority classes
+#define INTR_DIVIDE_BY_ZERO 0x00
+#define INTR_INVALID_OPCODE 0x06
+#define INTR_GPF 0x0d
+#define INTR_PAGE_FAULT 0x0e
+
+#define INTR_APICTIMER 0xf0
+#define INTR_KEYBOARD 0xe0
+
+#define INTR_DISK_PRIMARY 0xd0
+#define INTR_SPURIOUS 0xfe
+#define INTR_APICERR 0xff
+#define INTR_SHUTDOWN 0xfd
+
+/* NOTE: INTR_SYSCALL is not defined here, but is in syscall.h (it must be
+ * in a userland-accessible header) */
+
+// Intel Volume 3-A, 10.8.3.1 (10-29)
+#define IPL_LOW 0
+// we want to keep timer interrupts happening all the time to keep track of time
+// :)
+#define IPL_HIGH 0xe0
+#define IPL_HIGHEST 0xff
+
+typedef struct regs
+{
+ // all the regs
+ uint64_t r_r15;
+ uint64_t r_r14;
+ uint64_t r_r13;
+ uint64_t r_r12;
+ uint64_t r_rbp;
+ uint64_t r_rbx;
+ uint64_t r_r11;
+ uint64_t r_r10;
+ uint64_t r_r9;
+ uint64_t r_r8;
+ uint64_t r_rax;
+ uint64_t r_rcx;
+ uint64_t r_rdx;
+ uint64_t r_rsi;
+ uint64_t r_rdi;
+
+ // interrupt number
+ uint64_t r_intr;
+
+ // pushed by processor
+ uint64_t r_err;
+ uint64_t r_rip;
+ uint64_t r_cs;
+ uint64_t r_rflags;
+ uint64_t r_rsp;
+ uint64_t r_ss;
+} packed regs_t;
+
+void intr_init();
+
+/* The function pointer which should be implemented by functions
+ * which will handle interrupts. These handlers should be registered
+ * with the interrupt subsystem via the intr_register function.
+ * The regs structure contains the state of the registers saved when
+ * the interrupt occured. Return whether or not the handler has itself
+ * acknowledged the interrupt with a call to apic_eoi(). */
+typedef long (*intr_handler_t)(regs_t *regs);
+
+/* Registers an interrupt handler for the given interrupt handler.
+ * If another handler had been previously registered for this interrupt
+ * number it is returned, otherwise this function returns NULL. It
+ * is good practice to assert that this function returns NULL unless
+ * it is known that this will not be the case. */
+intr_handler_t intr_register(uint8_t intr, intr_handler_t handler);
+
+int32_t intr_map(uint16_t irq, uint8_t intr);
+
+static inline uint64_t intr_enabled()
+{
+ uint64_t flags;
+ __asm__ volatile("pushf; pop %0; and $0x200, %0;"
+ : "=r"(flags)::);
+ return flags;
+}
+
+static inline void intr_enable() { __asm__ volatile("sti"); }
+
+static inline void intr_disable() { __asm__ volatile("cli"); }
+
+/* Atomically enables interrupts using the sti
+ * instruction and puts the processor into a halted
+ * state, this function returns once an interrupt
+ * occurs. */
+static inline void intr_wait()
+{
+ /* the sti instruction enables interrupts, however
+ * interrupts are not checked for until the next
+ * instruction is executed, this means that the following
+ * code will not be succeptible to a bug where an
+ * interrupt occurs between the sti and hlt commands
+ * and does not wake us up from the hlt. */
+ __asm__ volatile("sti; hlt");
+}
+
+/* Sets the interrupt priority level for hardware interrupts.
+ * At initialization time devices should detect their individual
+ * IPLs and save them for use with this function. IPL_LOW allows
+ * all hardware interrupts. IPL_HIGH blocks all hardware interrupts */
+uint8_t intr_setipl(uint8_t ipl);
+
+/* Retreives the current interrupt priority level. */
+uint8_t intr_getipl();
+
+void dump_registers(regs_t *regs);
diff --git a/kernel/include/main/io.h b/kernel/include/main/io.h
new file mode 100644
index 0000000..19c6f86
--- /dev/null
+++ b/kernel/include/main/io.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "kernel.h"
+#include "types.h"
+
+static inline void outb(uint16_t port, uint8_t val)
+{
+ __asm__ volatile("outb %0,%1" ::"a"(val), "Nd"(port));
+}
+
+static inline uint8_t inb(uint16_t port)
+{
+ uint8_t ret;
+ __asm__ volatile("inb %1,%0"
+ : "=a"(ret)
+ : "Nd"(port));
+ return ret;
+}
+
+static inline void outw(uint16_t port, uint16_t val)
+{
+ __asm__ volatile("outw %0,%1" ::"a"(val), "Nd"(port));
+}
+
+static inline uint16_t inw(uint16_t port)
+{
+ uint16_t ret;
+ __asm__ volatile("inw %1,%0"
+ : "=a"(ret)
+ : "Nd"(port));
+ return ret;
+}
+
+static inline void outl(uint16_t port, uint32_t val)
+{
+ __asm__ volatile("outl %0,%1" ::"a"(val), "Nd"(port));
+}
+
+static inline uint32_t inl(uint16_t port)
+{
+ uint32_t ret;
+ __asm__ volatile("inl %1,%0"
+ : "=a"(ret)
+ : "Nd"(port));
+ return ret;
+}
diff --git a/kernel/include/main/smp.h b/kernel/include/main/smp.h
new file mode 100644
index 0000000..bf05fff
--- /dev/null
+++ b/kernel/include/main/smp.h
@@ -0,0 +1,22 @@
+#include "boot/config.h"
+#include "mm/page.h"
+#include "proc/core.h"
+
+// For any given piece of global data, there are 4 cases we must protect
+// against: (SMP.1) our core's other threads, (mutex or mask interrupts) (SMP.2)
+// our core's interrupt handlers, and (mask interrupts) (SMP.3) other cores'
+// threads, (mutex or spinlock) (SMP.4) other cores' interrupt handlers
+// (spinlock) mask interrupts + spinlock covers all 4 cases!
+
+#define GET_CSD(core, type, name) \
+ ((type *)(csd_vaddr_table[(core)] + PAGE_OFFSET(&(name))))
+
+extern uintptr_t csd_vaddr_table[];
+
+void map_in_core_specific_data(pml4_t *pml4);
+
+void smp_init();
+
+void core_init();
+
+long is_core_specific_data(void *addr);