aboutsummaryrefslogtreecommitdiff
path: root/kernel/main
diff options
context:
space:
mode:
authornthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
committernthnluu <nate1299@me.com>2024-01-28 21:20:27 -0500
commitc63f340d90800895f007de64b7d2d14624263331 (patch)
tree2c0849fa597dd6da831c8707b6f2603403778d7b /kernel/main
Created student weenix repository
Diffstat (limited to 'kernel/main')
-rw-r--r--kernel/main/acpi.c161
-rw-r--r--kernel/main/apic.c648
-rw-r--r--kernel/main/gdt.c129
-rw-r--r--kernel/main/gdt.gdb3
-rw-r--r--kernel/main/interrupt.c1077
-rw-r--r--kernel/main/kmain.c200
-rw-r--r--kernel/main/smp.c138
-rw-r--r--kernel/main/smp_trampoline.S81
8 files changed, 2437 insertions, 0 deletions
diff --git a/kernel/main/acpi.c b/kernel/main/acpi.c
new file mode 100644
index 0000000..cb0f221
--- /dev/null
+++ b/kernel/main/acpi.c
@@ -0,0 +1,161 @@
+#include "main/acpi.h"
+
+#include "boot/config.h"
+#include "mm/page.h"
+#include "types.h"
+#include "util/debug.h"
+#include "util/string.h"
+
+#define XSDT_SIGNATURE (*(uint32_t *)"XSDT")
+#define RSDT_SIGNATURE (*(uint32_t *)"RSDT")
+#define FACP_SIGNATURE (*(uint32_t *)"FACP")
+#define DSDT_SIGNATURE (*(uint32_t *)"DSDT")
+
+#define RSDP_ALIGN 16
+
+#define EBDA_MIN_PADDR 0x80000
+#define EBDA_MAX_PADDR 0xa0000
+#define EBDA_PTR_LOC_PADDR 0x040e
+
+#define EBDA_MIN (PHYS_OFFSET + EBDA_MIN_PADDR)
+#define EBDA_MAX (PHYS_OFFSET + EBDA_MAX_PADDR)
+#define EBDA_PTR_LOC (PHYS_OFFSET + EBDA_PTR_LOC_PADDR)
+
+static const uint8_t rsdp_sig[8] = {'R', 'S', 'D', ' ', 'P', 'T', 'R', ' '};
+
+typedef struct rsdp
+{
+ uint8_t rp_sign[8];
+ uint8_t rp_checksum;
+ uint8_t rp_oemid[6];
+ uint8_t rp_rev;
+ uint32_t rp_addr;
+} packed rsdp_t;
+
+typedef struct rsdp_20
+{
+ rsdp_t rsdp;
+ uint32_t length;
+ uint64_t xsdt_addr;
+ uint8_t ext_checksum;
+ uint8_t reserved[3];
+} packed rsdp_20_t;
+
+typedef struct rsd_table
+{
+ acpi_header_t rt_header;
+ uint64_t rt_other[];
+} packed rsd_table_t;
+
+static uint8_t __acpi_checksum(const uint8_t *buf, long size)
+{
+ uint8_t sum = 0;
+ for (long i = 0; i < size; i++)
+ sum += buf[i];
+ return sum;
+}
+
+static rsdp_20_t *__rsdp_search_range(uintptr_t start, uintptr_t end)
+{
+ uintptr_t rsdp_candidate = start;
+ while (rsdp_candidate <= end - sizeof(struct rsdp))
+ {
+ if (memcmp((void *)rsdp_candidate, rsdp_sig, sizeof(rsdp_sig)) == 0 &&
+ __acpi_checksum((uint8_t *)rsdp_candidate, sizeof(rsdp_20_t)) ==
+ 0)
+ {
+ return (rsdp_20_t *)rsdp_candidate;
+ }
+ rsdp_candidate += RSDP_ALIGN;
+ }
+ return NULL;
+}
+
+static void *__rsdp_search()
+{
+ // detect the location of the EBDA from the BIOS data section
+ uintptr_t ebda =
+ ((uintptr_t) * (uint16_t *)EBDA_PTR_LOC << 4) + PHYS_OFFSET;
+ rsdp_20_t *rsdp = 0;
+ if (ebda >= EBDA_MIN && ebda <= EBDA_MAX && ebda % RSDP_ALIGN == 0)
+ {
+ // check only if it's valid
+ rsdp = __rsdp_search_range(ebda, EBDA_MAX);
+ }
+ if (!rsdp)
+ {
+ // darmanio: unsure where these magic constants came from...
+ rsdp =
+ __rsdp_search_range(PHYS_OFFSET + 0xe0000, PHYS_OFFSET + 0x100000);
+ }
+ return rsdp;
+}
+
+static rsdp_20_t *rsd_ptr = NULL;
+static rsd_table_t *rsd_table = NULL;
+
+static rsd_table_t *_acpi_load_table(uintptr_t paddr)
+{
+ page_mark_reserved(PAGE_ALIGN_DOWN(paddr));
+ return (rsd_table_t *)(PHYS_OFFSET + paddr);
+}
+
+void acpi_init()
+{
+ if (rsd_ptr == NULL)
+ {
+ rsd_ptr = __rsdp_search();
+ KASSERT(rsd_ptr && "Could not find the ACPI Root Descriptor Table.");
+
+ rsd_table = _acpi_load_table(rsd_ptr->xsdt_addr);
+ KASSERT(XSDT_SIGNATURE == rsd_table->rt_header.ah_sign);
+ if (__acpi_checksum((void *)rsd_table, rsd_table->rt_header.ah_size))
+ {
+ panic("Weenix only supports ACPI 2.0 or higher");
+ }
+
+ dbgq(DBG_CORE, "--- ACPI INIT ---\n");
+ dbgq(DBG_CORE, "rsdp addr: %p\n", rsd_ptr);
+ dbgq(DBG_CORE, "rsdt addr: %p\n", rsd_table);
+ dbgq(DBG_CORE, "rev: %i\n", (int)rsd_ptr->rsdp.rp_rev);
+
+ rsd_ptr->rsdp.rp_oemid[5] = 0;
+ dbgq(DBG_CORE, "oem: %s\n", (char *)rsd_ptr->rsdp.rp_oemid);
+
+ // search for all tables listed in the RSDT and checksum them
+ dbgq(DBG_CORE, "ents:\t");
+ size_t headers =
+ (rsd_table->rt_header.ah_size - sizeof(rsd_table->rt_header)) /
+ sizeof(rsd_table->rt_other[0]);
+
+ for (size_t i = 0; i < headers; ++i)
+ {
+ acpi_header_t *header =
+ &_acpi_load_table(rsd_table->rt_other[i])->rt_header;
+ rsd_table->rt_other[i] = (uintptr_t)header;
+
+ dbgq(DBG_CORE, "%.4s ", (char *)&header->ah_sign);
+ KASSERT(0 == __acpi_checksum((void *)header, header->ah_size));
+ }
+ dbgq(DBG_CORE, "\n");
+ }
+}
+
+void *acpi_table(uint32_t signature, int index)
+{
+ KASSERT(index >= 0);
+
+ size_t headers =
+ (rsd_table->rt_header.ah_size - sizeof(rsd_table->rt_header)) /
+ sizeof(rsd_table->rt_other[0]);
+
+ for (size_t i = 0; i < headers; ++i)
+ {
+ acpi_header_t *header = (acpi_header_t *)rsd_table->rt_other[i];
+ if (header->ah_sign == signature && 0 == index--)
+ {
+ return header;
+ }
+ }
+ return NULL;
+}
diff --git a/kernel/main/apic.c b/kernel/main/apic.c
new file mode 100644
index 0000000..4d6f21c
--- /dev/null
+++ b/kernel/main/apic.c
@@ -0,0 +1,648 @@
+#include "types.h"
+
+#include "boot/config.h"
+
+#include "main/acpi.h"
+#include "main/apic.h"
+#include "main/cpuid.h"
+#include "main/interrupt.h"
+#include "main/io.h"
+
+#define APIC_SIGNATURE (*(uint32_t *)"APIC")
+
+#define TYPE_LAPIC 0
+#define TYPE_IOAPIC 1
+
+/* For disabling interrupts on the 8259 PIC, it needs to be
+ * disabled to use the APIC
+ */
+#define PIC_COMPLETE_MASK 0xff
+
+#define PIC1 0x20
+#define PIC1_COMMAND PIC1
+#define PIC1_DATA (PIC1 + 1)
+#define PIC1_VECTOR 0x20
+
+#define PIC2 0xa0
+#define PIC2_COMMAND PIC2
+#define PIC2_DATA (PIC2 + 1)
+#define PIC2_VECTOR 0x28
+
+#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
+#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
+#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
+#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
+#define ICW1_INIT 0x10 /* Initialization - required! */
+
+#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
+#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
+#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
+#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
+#define ICW4_SFNM 0x10 /* Special fully nested (not) */
+
+/* For enabling interrupts from the APIC rather than the
+ * Master PIC, use the Interrupt Mode Configuration Register (IMCR)
+ */
+
+#define SELECT_REGISTER 0x22
+#define IMCR_REGISTER 0x70
+#define ENABLE_APIC 0x23
+#define ENABLE_APIC_PORT 0x01
+
+/* For Local APICS */
+#define IA32_APIC_BASE_MSR 0x1b
+#define IA32_APIC_BASE_MSR_ENABLE 0x800
+#define LOCAL_APIC_SPURIOUS_REGISTER 0xf0
+#define LOCAL_APIC_ENABLE_INTERRUPT 0x100
+
+#define LOCAL_APIC_ID 0x20
+#define LOCAL_APIC_VERSION 0x30
+#define LOCAL_APIC_TASKPRIOR 0x80
+#define LOCAL_APIC_EOI 0xb0
+#define LOCAL_APIC_LDR 0xd0
+#define LOCAL_APIC_DFR 0xe0
+#define LOCAL_APIC_SPURIOUS 0xf0
+#define LOCAL_APIC_ESR 0x280
+#define LOCAL_APIC_ICRL 0x300
+#define LOCAL_APIC_ICRH 0x310
+#define LOCAL_APIC_LVT_TMR 0x320
+#define LOCAL_APIC_LVT_PERF 0x340
+#define LOCAL_APIC_LVT_LINT0 0x350
+#define LOCAL_APIC_LVT_LINT1 0x360
+#define LOCAL_APIC_LVT_ERR 0x370
+#define LOCAL_APIC_TMRINITCNT 0x380
+#define LOCAL_APIC_TMRCURRCNT 0x390
+#define LOCAL_APIC_TMRDIV 0x3e0
+#define LOCAL_APIC_LAST 0x38f
+#define LOCAL_APIC_DISABLE 0x10000
+#define LOCAL_APIC_SW_ENABLE 0x100
+#define LOCAL_APIC_CPUFOCUS 0x200
+#define LOCAL_APIC_NMI (4 << 8)
+#define LOCAL_APIC_TMR_PERIODIC 0x20000
+#define LOCAL_APIC_TMR_BASEDIV (1 << 20)
+
+#define APIC_ADDR (apic->at_addr + PHYS_OFFSET)
+#define APIC_REG(x) (*(uint32_t *)(APIC_ADDR + (x)))
+#define LAPICID APIC_REG(LOCAL_APIC_ID)
+#define LAPICVER APIC_REG(LOCAL_APIC_VERSION)
+#define LAPICTPR APIC_REG(LOCAL_APIC_TASKPRIOR)
+#define LAPICSPUR APIC_REG(LOCAL_APIC_SPURIOUS)
+#define LAPICEOI APIC_REG(LOCAL_APIC_EOI)
+#define LAPICDFR APIC_REG(LOCAL_APIC_DFR)
+#define LAPICLDR APIC_REG(LOCAL_APIC_LDR)
+#define LAPICLVTTMR APIC_REG(LOCAL_APIC_LVT_TMR)
+#define LAPICLVTPERF APIC_REG(LOCAL_APIC_LVT_PERF)
+#define LAPICLVTLINT0 APIC_REG(LOCAL_APIC_LVT_LINT0)
+#define LAPICLVTLINT1 APIC_REG(LOCAL_APIC_LVT_LINT1)
+#define LAPICLVTERR APIC_REG(LOCAL_APIC_LVT_ERR)
+#define LAPICTIC APIC_REG(LOCAL_APIC_TMRINITCNT)
+#define LAPICTCC APIC_REG(LOCAL_APIC_TMRCURRCNT)
+#define LAPICTMRDIV APIC_REG(LOCAL_APIC_TMRDIV)
+#define LAPICICRH APIC_REG(LOCAL_APIC_ICRH)
+#define LAPICICRL APIC_REG(LOCAL_APIC_ICRL)
+#define LAPICESR APIC_REG(LOCAL_APIC_ESR)
+
+/* IO APIC */
+#define IOAPIC_IOWIN 0x10
+
+/* Some configuration for the IO APIC */
+#define IOAPIC_ID 0x00
+#define IOAPIC_VER 0x01
+#define IOAPIC_ARB 0x02
+#define IOAPIC_REDTBL 0x03
+
+#define IOAPIC_ADDR (ioapic->at_addr + PHYS_OFFSET)
+#define IOAPIC (*(uint32_t *)IOAPIC_ADDR)
+#define IOAPICWIN (*(uint32_t *)(IOAPIC_ADDR + IOAPIC_IOWIN))
+
+/* Helpful Macros for IO APIC programming */
+#define BIT_SET(data, bit) \
+ do \
+ { \
+ (data) = ((data) | (0x1 << (bit))); \
+ } while (0);
+#define BIT_UNSET(data, bit) \
+ do \
+ { \
+ (data) = ((data) & ~(0x1 << (bit))); \
+ } while (0);
+
+#define IRQ_TO_OFFSET(irq, part) ((uint8_t)((0x10 + (irq * 2) + part)))
+
+typedef struct apic_table
+{
+ struct acpi_header at_header;
+ uint32_t at_addr;
+ uint32_t at_flags;
+} packed apic_table_t;
+
+typedef struct lapic_table
+{
+ uint8_t at_type;
+ uint8_t at_size;
+ uint8_t at_procid;
+ uint8_t at_apicid;
+ uint32_t at_flags;
+} packed lapic_table_t;
+
+typedef struct ioapic_table
+{
+ uint8_t at_type;
+ uint8_t at_size;
+ uint8_t at_apicid;
+ uint8_t at_reserved;
+ uint32_t at_addr;
+ uint32_t at_inti;
+} packed ioapic_table_t;
+
+static apic_table_t *apic = NULL;
+static ioapic_table_t *ioapic = NULL;
+
+// Use MAX_LAPICS + 1 entries so we can guarantee the last entry is null
+static lapic_table_t *lapics[MAX_LAPICS + 1] = {NULL};
+static long max_apicid;
+
+static long initialized = 0;
+
+// Returns the maximum APIC ID
+inline long apic_max_id() { return max_apicid; }
+
+/* [APIC ID------------------------] */
+inline static long __lapic_getid(void) { return (LAPICID >> 24) & 0xff; }
+
+// Returns the APIC ID of the current processor/core
+inline long apic_current_id() { return __lapic_getid(); }
+
+inline static uint32_t __lapic_getver(void) { return LAPICVER & 0xff; }
+
+inline static void __lapic_setspur(uint8_t intr)
+{
+ uint32_t data = LAPICSPUR | LOCAL_APIC_SW_ENABLE;
+ *((uint8_t *)&data) = intr;
+ LAPICSPUR = data;
+}
+
+/* [LOGICID-------------------------] */
+inline static void __lapic_setlogicalid(uint8_t id)
+{
+ LAPICLDR = ((uint32_t)id) << 24;
+}
+
+inline static uint32_t ioapic_read(uint8_t reg_offset)
+{
+ /* Tell IOREGSEL where we want to read from */
+ IOAPIC = reg_offset;
+ return IOAPICWIN;
+}
+
+inline static void ioapic_write(uint8_t reg_offset, uint32_t value)
+{
+ /* Tell IOREGSEL where to write to */
+ IOAPIC = reg_offset;
+ /* Write the value to IOWIN */
+ IOAPICWIN = value;
+}
+
+inline static uint32_t __ioapic_getid(void)
+{
+ return (ioapic_read(IOAPIC_ID) >> 24) & 0x0f;
+}
+
+inline static uint32_t __ioapic_getver(void)
+{
+ return ioapic_read(IOAPIC_VER) & 0xff;
+}
+
+inline static uint32_t __ioapic_getmaxredir(void)
+{
+ return (ioapic_read(IOAPIC_VER) >> 16) & 0xff;
+}
+
+inline static void __ioapic_setredir(uint32_t irq, uint8_t intr)
+{
+ /* Read in the redirect table lower register first */
+ uint32_t data = ioapic_read(IRQ_TO_OFFSET(irq, 0));
+ /* Set the interrupt vector */
+ ((uint8_t *)&data)[0] = intr;
+ /* Set bit 8, unset bits 9,10 to set interrupt delivery mode to lowest
+ * priority */
+ BIT_SET(data, 8);
+ BIT_UNSET(data, 9);
+ BIT_UNSET(data, 10);
+ /* Set bit 11 to set the destination mode to a logical destination */
+ BIT_SET(data, 11);
+ /* Unset bit 13 to set the pin polarity to Active High */
+ BIT_UNSET(data, 13);
+ /* Unset bit 15 to set the trigger mode to Edge */
+ BIT_UNSET(data, 15);
+ /* Write this value to the apic */
+ ioapic_write(IRQ_TO_OFFSET(irq, 0), data);
+ /* Now deal with the higher order register */
+ data = ioapic_read(IRQ_TO_OFFSET(irq, 1));
+ ((uint8_t *)&data)[3] = 0xff;
+ ioapic_write(IRQ_TO_OFFSET(irq, 1), data);
+}
+
+inline static void __ioapic_setmask(uint32_t irq, int mask)
+{
+ uint32_t data = ioapic_read(IRQ_TO_OFFSET(irq, 0));
+ if (mask)
+ {
+ BIT_SET(data, 16);
+ }
+ else
+ {
+ BIT_UNSET(data, 16);
+ }
+ ioapic_write(IRQ_TO_OFFSET(irq, 0), data);
+}
+
+static uint32_t apic_exists(void)
+{
+ uint32_t eax, ebx, ecx, edx;
+ cpuid(CPUID_GETFEATURES, &eax, &ebx, &ecx, &edx);
+ return edx & CPUID_FEAT_EDX_APIC;
+}
+
+static void apic_set_base(uint32_t apic)
+{
+ uint32_t edx = 0;
+ uint32_t eax = (apic & 0xfffff000) | IA32_APIC_BASE_MSR_ENABLE;
+ edx = 0;
+ cpuid_set_msr(IA32_APIC_BASE_MSR, eax, edx);
+}
+
+static uint32_t apic_get_base(void)
+{
+ uint32_t eax, edx;
+ cpuid_get_msr(IA32_APIC_BASE_MSR, &eax, &edx);
+ return (eax & 0xfffff000);
+}
+
+static long __apic_err()
+{
+ dbg(DBG_PRINT, "[+] APIC Error: 0x%d", LAPICESR);
+ __asm__("cli; hlt");
+ return 0;
+}
+
+void apic_enable()
+{
+ // [MODE---------------------------]
+ // L
+ LAPICDFR = 0xffffffff;
+
+ KASSERT(apic_current_id() < 8);
+ __lapic_setlogicalid((uint8_t)(1 << apic_current_id()));
+ LAPICLVTTMR = LOCAL_APIC_DISABLE;
+ LAPICLVTPERF = LOCAL_APIC_NMI;
+ LAPICLVTLINT0 = LOCAL_APIC_DISABLE;
+ LAPICLVTLINT1 = LOCAL_APIC_DISABLE;
+ LAPICLVTERR = INTR_APICERR;
+ LAPICTPR = 0;
+ apic_set_base(apic_get_base());
+ apic_setspur(INTR_SPURIOUS);
+ intr_register(INTR_APICERR, __apic_err);
+}
+
+void apic_disable_periodic_timer()
+{
+ LAPICLVTTMR = LOCAL_APIC_DISABLE;
+ LAPICLVTPERF = LOCAL_APIC_NMI;
+ LAPICLVTLINT0 = LOCAL_APIC_DISABLE;
+ LAPICLVTLINT1 = LOCAL_APIC_DISABLE;
+ LAPICTPR = 0;
+}
+
+/* get_cpu_bus_frequency - Uses PIT to determine APIC frequency in Hz (ticks per
+ * second). NOTE: NOT SMP FRIENDLY! Note: For more info, visit the osdev wiki
+ * page on the Programmable Interval Timer. */
+static uint32_t get_cpu_bus_frequency()
+{
+ static uint32_t freq = 0;
+ if (!freq)
+ {
+ /* Division rate: 0b1011 corresponds to division by 1, which does
+ * nothing. */
+ LAPICTMRDIV = 0b1011;
+
+ /* 0x61 controls the PC speaker.
+ * Clearing bit 1 prevents any sound.
+ * Setting bit 0 connects the speaker to the output of PIT channel 2. */
+ outb(0x61, (uint8_t)((inb(0x61) & 0xfd) | 1));
+
+ /* Control reg:
+ * 0x1011 = Channel 2, lobyte/hibyte access
+ * 0x0010 = Mode 1 (hardware one-shot) */
+ outb(0x43, 0xb2);
+
+ /* Not sure why there's an inb, but the two outb send the reload value:
+ * 0x2e9b = 11931, aka 1/100th of the PIT oscillator rate, aka 10 ms. */
+ outb(0x42, 0x9b);
+ inb(0x60);
+ outb(0x42, 0x2e);
+
+ /* Reset the one-shot counter by clearing and resetting bit 0. */
+ uint32_t tmp = (uint32_t)(inb(0x61) & 0xfe);
+ outb(0x61, (uint8_t)tmp);
+ outb(0x61, (uint8_t)(tmp | 1));
+ /* Reset APIC's initial countdown value. */
+ LAPICTIC = 0xffffffff;
+ /* PC speaker sets bit 5 when it hits 0. */
+ while (!(inb(0x61) & 0x20))
+ ;
+ /* Stop the APIC timer */
+ LAPICLVTTMR = LOCAL_APIC_DISABLE;
+ /* Subtract current count from the initial count to get total ticks per
+ * second. */
+ freq = (LAPICTIC - LAPICTCC) * 100;
+ dbgq(DBG_CORE, "CPU Bus Freq: %u ticks per second\n", freq);
+ }
+ return freq;
+}
+
+/* apic_enable_periodic_timer - Starts the periodic timer (continuously send
+ * interrupts) at a given frequency. For more information, refer to: Intel
+ * System Programming Guide, Vol 3A Part 1, 10.5.4. */
+void apic_enable_periodic_timer(uint32_t freq)
+{
+ // TODO: Check this math! Don't assume it's correct...
+
+ uint32_t ticks_per_second = get_cpu_bus_frequency();
+ /* Demand at least the desired precision. */
+ if (ticks_per_second < freq)
+ {
+ panic(
+ "apic timer is not precise enough for desired frequency\n");
+ }
+
+ /* TODO: Pretty sure this can be more precise using the initial count
+ * properly. */
+
+ /* Round the bus frequency down to the nearest multiple of the desired
+ * frequency. If bus/freq is large, the remainder will get amortized to a
+ * degree that should be acceptable for Weenix. */
+ uint32_t rem = ticks_per_second % freq;
+ if (rem > (freq / 2))
+ ticks_per_second += (freq - rem);
+ else
+ ticks_per_second -= rem;
+ // TODO: Provide a warning when there is a lot of drift, e.g. more than
+ // 1/10th inaccuracy per interval
+
+ /* Divide configuration. */
+ uint32_t div = 0b0111; /* Starts at division by 1. */
+ uint32_t tmp = ticks_per_second;
+ for (int i = 1; i < 7; i++)
+ { /* Max division is 2^7. */
+ /* Don't cut the freq in half if it would ruin divisibility. */
+ if ((tmp >> 1) % freq != 0)
+ break;
+ if ((tmp >> 1) < freq)
+ break;
+ /* Cut freq in half. */
+ tmp >>= 1;
+ /* Increment the order of division (1, 2, 4, ...). */
+ div++;
+ }
+
+ uint32_t tmpdiv = div;
+
+ /* Clear bit 3, which probably artificially overflowed. */
+ div &= 0b0111;
+
+ /* APIC DIV register skips bit 2, so if set, move it to bit 3. */
+ if (div & 0b0100)
+ {
+ div &= 0b0011; /* Clear bit 2. */
+ div |= 0b1011; /* Set bit 3. */
+ }
+
+ /* Set up three registers to configure timer:
+ * 1) Initial count: count down from this value, send interrupt upon hitting
+ * 0. */
+ LAPICTIC = tmp / freq;
+ /* 3) Divide config: calculated above to cut bus clock. */
+ LAPICTMRDIV = div;
+ /* 2) LVT timer: use a periodic timer and raise the provided interrupt
+ * vector. */
+ LAPICLVTTMR = LOCAL_APIC_TMR_PERIODIC | INTR_APICTIMER;
+}
+
+static void apic_disable_8259()
+{
+ dbgq(DBG_CORE, "--- DISABLE 8259 PIC ---\n");
+ /* disable 8259 PICs by initializing them and masking all interrupts */
+ /* the first step is initialize them normally */
+ outb(PIC1_COMMAND, ICW1_INIT + ICW1_ICW4);
+ io_wait();
+ outb(PIC2_COMMAND, ICW1_INIT + ICW1_ICW4);
+ io_wait();
+ outb(PIC1_DATA, PIC1_VECTOR);
+ io_wait();
+ outb(PIC2_DATA, PIC2_VECTOR);
+ io_wait();
+ outb(PIC1_DATA, 0x04);
+ io_wait();
+ outb(PIC2_DATA, 0x02);
+ io_wait();
+ outb(PIC1_DATA, ICW4_8086);
+ io_wait();
+ outb(PIC2_DATA, ICW4_8086);
+ /* Now mask all interrupts */
+ dbgq(DBG_CORE, "Masking all interrupts on the i8259 PIC\n");
+ outb(PIC1_DATA, PIC_COMPLETE_MASK);
+ outb(PIC2_DATA, PIC_COMPLETE_MASK);
+}
+
+static void map_apic_addr(uintptr_t paddr)
+{
+ page_mark_reserved((void *)paddr);
+ pt_map(pt_get(), paddr, paddr + PHYS_OFFSET, PT_WRITE | PT_PRESENT,
+ PT_WRITE | PT_PRESENT);
+}
+
+void apic_init()
+{
+ uint8_t *ptr = acpi_table(APIC_SIGNATURE, 0);
+ apic = (apic_table_t *)ptr;
+ KASSERT(NULL != apic && "APIC table not found in ACPI.");
+
+ apic_disable_8259();
+
+ dbgq(DBG_CORE, "--- APIC INIT ---\n");
+ dbgq(DBG_CORE, "local apic paddr: 0x%x\n", apic->at_addr);
+ dbgq(DBG_CORE, "PC-AT compatible: %i\n", apic->at_flags & 0x1);
+ KASSERT(PAGE_ALIGNED((void *)(uintptr_t)apic->at_addr));
+
+ KASSERT(apic->at_addr < 0xffffffff);
+
+ map_apic_addr(apic->at_addr);
+
+ /* Get the tables for the local APIC and IO APICS */
+ uint8_t off = sizeof(*apic);
+ while (off < apic->at_header.ah_size)
+ {
+ uint8_t type = *(ptr + off);
+ uint8_t size = *(ptr + off + 1);
+ lapic_table_t *lapic = NULL;
+ if (TYPE_LAPIC == type)
+ {
+ KASSERT(apic_exists() && "Local APIC does not exist");
+ KASSERT(sizeof(lapic_table_t) == size);
+ lapic = (lapic_table_t *)(ptr + off);
+ KASSERT(lapic->at_apicid < MAX_LAPICS &&
+ "Weenix only supports MAX_LAPICS local APICs");
+ lapics[lapic->at_apicid] = lapic;
+
+ page_mark_reserved(PAGE_ALIGN_DOWN((uintptr_t)lapic - PHYS_OFFSET));
+ max_apicid = lapic->at_apicid;
+
+ dbgq(DBG_CORE, "LAPIC:\n");
+ dbgq(DBG_CORE, " id: 0x%.2x\n",
+ (uint32_t)lapic->at_apicid);
+ dbgq(DBG_CORE, " processor: 0x%.3x\n",
+ (uint32_t)lapic->at_procid);
+ dbgq(DBG_CORE, " enabled: %i\n", apic->at_flags & 0x1);
+ }
+ else if (TYPE_IOAPIC == type)
+ {
+ KASSERT(apic_exists() && "IO APIC does not exist");
+ KASSERT(sizeof(ioapic_table_t) == size);
+ KASSERT(NULL == ioapic && "Weenix only supports a single IO APIC");
+ ioapic = (ioapic_table_t *)(ptr + off);
+ page_mark_reserved(
+ PAGE_ALIGN_DOWN((uintptr_t)ioapic - PHYS_OFFSET));
+ map_apic_addr(ioapic->at_addr);
+
+ dbgq(DBG_CORE, "IOAPIC:\n");
+ dbgq(DBG_CORE, " id: 0x%.2x\n",
+ (uint32_t)ioapic->at_apicid);
+ dbgq(DBG_CORE, " base paddr: 0x%.8x\n", ioapic->at_addr);
+ dbgq(DBG_CORE, " inti addr: 0x%.8x\n", ioapic->at_inti);
+ KASSERT(PAGE_ALIGNED((void *)(uintptr_t)ioapic->at_addr));
+ }
+ else
+ {
+ dbgq(DBG_CORE, "Unknown APIC type: 0x%x\n", (uint32_t)type);
+ }
+ off += size;
+ }
+ KASSERT(NULL != lapics[apic_current_id()] &&
+ "Could not find a local APIC device");
+ KASSERT(NULL != ioapic && "Could not find an IO APIC");
+
+ initialized = 1;
+}
+
+inline long apic_initialized() { return initialized; }
+
+inline uint8_t apic_getipl() { return (uint8_t)LAPICTPR; }
+
+inline void apic_setipl(uint8_t ipl) { LAPICTPR = ipl; }
+
+inline void apic_setspur(uint8_t intr)
+{
+ dbg(DBG_CORE, "mapping spurious interrupts to %u\n", intr);
+ __lapic_setspur(intr);
+}
+
+inline void apic_eoi() { LAPICEOI = 0x0; }
+
+void apic_setredir(uint32_t irq, uint8_t intr)
+{
+ dbg(DBG_CORE, "redirecting irq %u to interrupt %u\n", irq, intr);
+ __ioapic_setredir(irq, intr);
+ __ioapic_setmask(irq, 0);
+}
+
+void apic_start_processor(uint8_t processor, uint8_t execution_page)
+{
+ // [+] TODO FIX MAGIC NUMBERS
+ KASSERT(processor < 8);
+ uint32_t icr_low = 0;
+ icr_low |= 0;
+ icr_low |= DESTINATION_MODE_INIT << 8;
+ BIT_UNSET(icr_low, 11); // physical destination
+
+ BIT_SET(icr_low, 14);
+ BIT_UNSET(icr_low, 15);
+
+ dbg(DBG_CORE, "Sending IPI: ICR_LOW = 0x%.8x, ICR_HIGH = 0x%.8x\n", icr_low,
+ processor << 24);
+ LAPICICRH = processor << 24;
+ LAPICICRL = icr_low;
+
+ apic_wait_ipi();
+
+ icr_low = 0;
+ icr_low |= execution_page;
+ icr_low |= DESTINATION_MODE_SIPI << 8;
+ BIT_UNSET(icr_low, 11); // physical destination
+
+ BIT_SET(icr_low, 14);
+ BIT_UNSET(icr_low, 15);
+ dbg(DBG_CORE, "Sending IPI: ICR_LOW = 0x%.8x, ICR_HIGH = 0x%.8x\n", icr_low,
+ processor << 24);
+
+ LAPICICRH = processor << 24;
+ LAPICICRL = icr_low;
+
+ apic_wait_ipi();
+}
+
+void apic_send_ipi(uint8_t target, ipi_destination_mode mode, uint8_t vector)
+{
+ // See https://wiki.osdev.org/APIC#Interrupt_Command_Register for a
+ // description of how this works. This function only supports targeting a
+ // single APIC, instead of using the special destination modes. Since we
+ // already parse the APIC table, it's more reliable to interrupt a specific
+ // processor.
+ KASSERT(target < 8);
+
+ uint32_t icr_low = 0;
+ icr_low |= vector; // bits 0-7 are the vector number
+ icr_low |= mode << 8; // bits 8-10 are the destination mode
+ BIT_SET(icr_low, 11); // logical destination
+
+ BIT_SET(icr_low, 14);
+
+ dbgq(DBG_CORE, "Sending IPI: ICR_LOW = 0x%.8x, ICR_HIGH = 0x%.8x\n",
+ icr_low, (1U << target) << 24);
+
+ // Bits 24-27 of ICR_HIGH are the target logical APIC ID. Setting ICR_LOW
+ // sends the interrupt, so we have to set this first
+ LAPICICRH = (1U << target) << 24;
+ // send the IPI
+ LAPICICRL = icr_low;
+}
+
+void apic_broadcast_ipi(ipi_destination_mode mode, uint8_t vector,
+ long include_self)
+{
+ uint32_t icr_low = 0;
+ icr_low |= vector;
+ icr_low |= mode << 8;
+ BIT_SET(icr_low, 11);
+ BIT_SET(icr_low, 14);
+
+ if (!include_self)
+ BIT_SET(icr_low, 18);
+ BIT_SET(icr_low, 19);
+
+ LAPICICRH = 0;
+ LAPICICRL = icr_low;
+}
+
+/**
+ * Wait for the last IPI sent to be acknowledged by the other processor.
+ *
+ * Note: this is separate from apic_send_ipi because there are circumstances
+ * where we don't want to wait.
+ */
+void apic_wait_ipi()
+{
+ // Bit 12 of ICR_LOW is the delivery status flag.
+ while (LAPICICRL & (1 << 12))
+ ;
+}
diff --git a/kernel/main/gdt.c b/kernel/main/gdt.c
new file mode 100644
index 0000000..9bc8282
--- /dev/null
+++ b/kernel/main/gdt.c
@@ -0,0 +1,129 @@
+#include "main/gdt.h"
+#include "globals.h"
+
+#include "util/debug.h"
+#include "util/printf.h"
+#include "util/string.h"
+
+typedef struct gdt_entry
+{
+ uint16_t ge_limitlo;
+ uint16_t ge_baselo;
+ uint8_t ge_basemid;
+ uint8_t ge_access;
+ uint8_t ge_flags;
+ uint8_t ge_basehi;
+} packed gdt_entry_t;
+
+static gdt_entry_t gdt[GDT_COUNT] CORE_SPECIFIC_DATA;
+
+typedef struct tss_entry
+{
+ uint32_t ts_reserved1;
+ uint64_t ts_rsp0;
+ uint64_t ts_rsp1;
+ uint64_t ts_rsp2;
+ uint64_t ts_reserved2;
+ uint64_t ts_ist1;
+ uint64_t ts_ist2;
+ uint64_t ts_ist3;
+ uint64_t ts_ist4;
+ uint64_t ts_ist5;
+ uint64_t ts_ist6;
+ uint64_t ts_ist7;
+ uint64_t ts_reserved3;
+ uint16_t ts_iopb;
+ uint16_t ts_reserved4;
+} packed tss_entry_t;
+
+typedef struct gdt_location
+{
+ uint16_t gl_size;
+ uint64_t gl_offset;
+} packed gdt_location_t;
+
+static gdt_location_t gdtl = {.gl_size = GDT_COUNT * sizeof(gdt_entry_t),
+ .gl_offset = (uint64_t)&gdt};
+
+static tss_entry_t tss CORE_SPECIFIC_DATA;
+
+void gdt_init(void)
+{
+ memset(gdt, 0, sizeof(gdt));
+ gdt_set_entry(GDT_KERNEL_TEXT, 0x0, 0xFFFFF, 0, 1, 0, 1);
+ gdt_set_entry(GDT_KERNEL_DATA, 0x0, 0xFFFFF, 0, 0, 0, 1);
+ gdt_set_entry(GDT_USER_TEXT, 0x0, 0xFFFFF, 3, 1, 0, 1);
+ gdt_set_entry(GDT_USER_DATA, 0x0, 0xFFFFF, 3, 0, 0, 1);
+
+ uintptr_t tss_pointer = (uintptr_t)&tss;
+ gdt_set_entry(GDT_TSS, (uint32_t)tss_pointer, sizeof(tss), 0, 1, 0, 0);
+ gdt[GDT_TSS / 8].ge_access &= ~(0b10000);
+ gdt[GDT_TSS / 8].ge_access |= 0b1;
+ gdt[GDT_TSS / 8].ge_flags &= ~(0b10000000);
+
+ uint64_t tss_higher_half = ((uint64_t)tss_pointer) >> 32;
+ memcpy(&gdt[GDT_TSS / 8 + 1], &tss_higher_half, 8);
+
+ memset(&tss, 0, sizeof(tss));
+ tss.ts_iopb = sizeof(tss);
+
+ gdt_location_t *data = &gdtl;
+ int segment = GDT_TSS;
+
+ dbg(DBG_CORE, "Installing GDT and TR\n");
+ __asm__ volatile("lgdt (%0); ltr %1" ::"p"(data), "m"(segment));
+}
+
+void gdt_set_kernel_stack(void *addr) { tss.ts_rsp0 = (uint64_t)addr; }
+
+void gdt_set_entry(uint32_t segment, uint32_t base, uint32_t limit,
+ uint8_t ring, int exec, int dir, int rw)
+{
+ KASSERT(segment < GDT_COUNT * 8 && 0 == segment % 8);
+ KASSERT(ring <= 3);
+ KASSERT(limit <= 0xFFFFF);
+
+ int index = segment / 8;
+ gdt[index].ge_limitlo = (uint16_t)limit;
+ gdt[index].ge_baselo = (uint16_t)base;
+ gdt[index].ge_basemid = (uint8_t)(base >> 16);
+ gdt[index].ge_basehi = (uint8_t)(base >> 24);
+
+ // For x86-64, set the L bit to indicate a 64-bit descriptor and clear Sz
+ // Having both L and Sz set is reserved for future use
+ gdt[index].ge_flags = (uint8_t)(0b10100000 | (limit >> 16));
+
+ gdt[index].ge_access = 0b10000000;
+ gdt[index].ge_access |= (ring << 5);
+ gdt[index].ge_access |= 0b10000;
+ if (exec)
+ {
+ gdt[index].ge_access |= 0b1000;
+ }
+ if (dir)
+ {
+ gdt[index].ge_access |= 0b100;
+ }
+ if (rw)
+ {
+ gdt[index].ge_access |= 0b10;
+ }
+}
+
+void gdt_clear(uint32_t segment)
+{
+ KASSERT(segment < GDT_COUNT * 8 && 0 == segment % 8);
+ memset(&gdt[segment / 8], 0, sizeof(gdt[segment / 8]));
+}
+
+size_t gdt_tss_info(const void *arg, char *buf, size_t osize)
+{
+ size_t size = osize;
+
+ KASSERT(NULL == arg);
+
+ iprintf(&buf, &size, "TSS:\n");
+ iprintf(&buf, &size, "kstack: 0x%p\n", (void *)tss.ts_rsp0);
+
+ return size;
+}
diff --git a/kernel/main/gdt.gdb b/kernel/main/gdt.gdb
new file mode 100644
index 0000000..9dbf37a
--- /dev/null
+++ b/kernel/main/gdt.gdb
@@ -0,0 +1,3 @@
+define tss
+ kinfo gdt_tss_info
+end
diff --git a/kernel/main/interrupt.c b/kernel/main/interrupt.c
new file mode 100644
index 0000000..d3f6655
--- /dev/null
+++ b/kernel/main/interrupt.c
@@ -0,0 +1,1077 @@
+#include "errno.h"
+#include "globals.h"
+#include "types.h"
+#include <api/syscall.h>
+
+#include "util/debug.h"
+#include "util/string.h"
+
+#include "main/apic.h"
+#include "main/gdt.h"
+
+#define MAX_INTERRUPTS 256
+
+/* Convenient definitions for intr_desc.attr */
+
+#define IDT_DESC_TRAP 0x01
+#define IDT_DESC_BIT16 0x06
+#define IDT_DESC_BIT32 0x0E
+#define IDT_DESC_RING0 0x00
+#define IDT_DESC_RING1 0x40
+#define IDT_DESC_RING2 0x20
+#define IDT_DESC_RING3 0x60
+#define IDT_DESC_PRESENT 0x80
+
+#define INTR(isr) (__intr_handler##isr)
+
+#define INTR_ERRCODE(isr) \
+ extern intr_handler_t __intr_handler##isr; \
+ __asm__(".global __intr_handler" #isr \
+ "\n" \
+ "__intr_handler" #isr \
+ ":\n\t" \
+ "pushq $" #isr \
+ "\n\t" \
+ "pushq %rdi\n\t" \
+ "pushq %rsi\n\t" \
+ "pushq %rdx\n\t" \
+ "pushq %rcx\n\t" \
+ "pushq %rax\n\t" \
+ "pushq %r8\n\t" \
+ "pushq %r9\n\t" \
+ "pushq %r10\n\t" \
+ "pushq %r11\n\t" \
+ "pushq %rbx\n\t" \
+ "pushq %rbp\n\t" \
+ "pushq %r12\n\t" \
+ "pushq %r13\n\t" \
+ "pushq %r14\n\t" \
+ "pushq %r15\n\t" \
+ "call interrupt_handler\n\t" \
+ "popq %r15\n\t" \
+ "popq %r14\n\t" \
+ "popq %r13\n\t" \
+ "popq %r12\n\t" \
+ "popq %rbp\n\t" \
+ "popq %rbx\n\t" \
+ "popq %r11\n\t" \
+ "popq %r10\n\t" \
+ "popq %r9\n\t" \
+ "popq %r8\n\t" \
+ "popq %rax\n\t" \
+ "popq %rcx\n\t" \
+ "popq %rdx\n\t" \
+ "popq %rsi\n\t" \
+ "popq %rdi\n\t" \
+ "add $16, %rsp\n\t" \
+ "iretq\n");
+
+#define INTR_NOERRCODE(isr) \
+ extern intr_handler_t __intr_handler##isr; \
+ __asm__(".global __intr_handler" #isr \
+ "\n" \
+ "__intr_handler" #isr \
+ ":\n\t" \
+ "pushq $0x0\n\t" \
+ "pushq $" #isr \
+ "\n\t" \
+ "pushq %rdi\n\t" \
+ "pushq %rsi\n\t" \
+ "pushq %rdx\n\t" \
+ "pushq %rcx\n\t" \
+ "pushq %rax\n\t" \
+ "pushq %r8\n\t" \
+ "pushq %r9\n\t" \
+ "pushq %r10\n\t" \
+ "pushq %r11\n\t" \
+ "pushq %rbx\n\t" \
+ "pushq %rbp\n\t" \
+ "pushq %r12\n\t" \
+ "pushq %r13\n\t" \
+ "pushq %r14\n\t" \
+ "pushq %r15\n\t" \
+ "call interrupt_handler\n\t" \
+ "popq %r15\n\t" \
+ "popq %r14\n\t" \
+ "popq %r13\n\t" \
+ "popq %r12\n\t" \
+ "popq %rbp\n\t" \
+ "popq %rbx\n\t" \
+ "popq %r11\n\t" \
+ "popq %r10\n\t" \
+ "popq %r9\n\t" \
+ "popq %r8\n\t" \
+ "popq %rax\n\t" \
+ "popq %rcx\n\t" \
+ "popq %rdx\n\t" \
+ "popq %rsi\n\t" \
+ "popq %rdi\n\t" \
+ "add $16, %rsp\n\t" \
+ "iretq\n\t");
+
+INTR_NOERRCODE(0)
+INTR_NOERRCODE(1)
+INTR_NOERRCODE(2)
+INTR_NOERRCODE(3)
+INTR_NOERRCODE(4)
+INTR_NOERRCODE(5)
+INTR_NOERRCODE(6)
+INTR_NOERRCODE(7)
+INTR_ERRCODE(8)
+INTR_NOERRCODE(9)
+INTR_ERRCODE(10)
+INTR_ERRCODE(11)
+INTR_ERRCODE(12)
+INTR_ERRCODE(13)
+INTR_ERRCODE(14)
+INTR_NOERRCODE(15)
+INTR_NOERRCODE(16)
+INTR_ERRCODE(17)
+INTR_NOERRCODE(18)
+INTR_NOERRCODE(19)
+INTR_NOERRCODE(20)
+INTR_NOERRCODE(21)
+INTR_NOERRCODE(22)
+INTR_NOERRCODE(23)
+INTR_NOERRCODE(24)
+INTR_NOERRCODE(25)
+INTR_NOERRCODE(26)
+INTR_NOERRCODE(27)
+INTR_NOERRCODE(28)
+INTR_NOERRCODE(29)
+INTR_NOERRCODE(30)
+INTR_NOERRCODE(31)
+INTR_NOERRCODE(32)
+INTR_NOERRCODE(33)
+INTR_NOERRCODE(34)
+INTR_NOERRCODE(35)
+INTR_NOERRCODE(36)
+INTR_NOERRCODE(37)
+INTR_NOERRCODE(38)
+INTR_NOERRCODE(39)
+INTR_NOERRCODE(40)
+INTR_NOERRCODE(41)
+INTR_NOERRCODE(42)
+INTR_NOERRCODE(43)
+INTR_NOERRCODE(44)
+INTR_NOERRCODE(45)
+INTR_NOERRCODE(46)
+INTR_NOERRCODE(47)
+INTR_NOERRCODE(48)
+INTR_NOERRCODE(49)
+INTR_NOERRCODE(50)
+INTR_NOERRCODE(51)
+INTR_NOERRCODE(52)
+INTR_NOERRCODE(53)
+INTR_NOERRCODE(54)
+INTR_NOERRCODE(55)
+INTR_NOERRCODE(56)
+INTR_NOERRCODE(57)
+INTR_NOERRCODE(58)
+INTR_NOERRCODE(59)
+INTR_NOERRCODE(60)
+INTR_NOERRCODE(61)
+INTR_NOERRCODE(62)
+INTR_NOERRCODE(63)
+INTR_NOERRCODE(64)
+INTR_NOERRCODE(65)
+INTR_NOERRCODE(66)
+INTR_NOERRCODE(67)
+INTR_NOERRCODE(68)
+INTR_NOERRCODE(69)
+INTR_NOERRCODE(70)
+INTR_NOERRCODE(71)
+INTR_NOERRCODE(72)
+INTR_NOERRCODE(73)
+INTR_NOERRCODE(74)
+INTR_NOERRCODE(75)
+INTR_NOERRCODE(76)
+INTR_NOERRCODE(77)
+INTR_NOERRCODE(78)
+INTR_NOERRCODE(79)
+INTR_NOERRCODE(80)
+INTR_NOERRCODE(81)
+INTR_NOERRCODE(82)
+INTR_NOERRCODE(83)
+INTR_NOERRCODE(84)
+INTR_NOERRCODE(85)
+INTR_NOERRCODE(86)
+INTR_NOERRCODE(87)
+INTR_NOERRCODE(88)
+INTR_NOERRCODE(89)
+INTR_NOERRCODE(90)
+INTR_NOERRCODE(91)
+INTR_NOERRCODE(92)
+INTR_NOERRCODE(93)
+INTR_NOERRCODE(94)
+INTR_NOERRCODE(95)
+INTR_NOERRCODE(96)
+INTR_NOERRCODE(97)
+INTR_NOERRCODE(98)
+INTR_NOERRCODE(99)
+INTR_NOERRCODE(100)
+INTR_NOERRCODE(101)
+INTR_NOERRCODE(102)
+INTR_NOERRCODE(103)
+INTR_NOERRCODE(104)
+INTR_NOERRCODE(105)
+INTR_NOERRCODE(106)
+INTR_NOERRCODE(107)
+INTR_NOERRCODE(108)
+INTR_NOERRCODE(109)
+INTR_NOERRCODE(110)
+INTR_NOERRCODE(111)
+INTR_NOERRCODE(112)
+INTR_NOERRCODE(113)
+INTR_NOERRCODE(114)
+INTR_NOERRCODE(115)
+INTR_NOERRCODE(116)
+INTR_NOERRCODE(117)
+INTR_NOERRCODE(118)
+INTR_NOERRCODE(119)
+INTR_NOERRCODE(120)
+INTR_NOERRCODE(121)
+INTR_NOERRCODE(122)
+INTR_NOERRCODE(123)
+INTR_NOERRCODE(124)
+INTR_NOERRCODE(125)
+INTR_NOERRCODE(126)
+INTR_NOERRCODE(127)
+INTR_NOERRCODE(128)
+INTR_NOERRCODE(129)
+INTR_NOERRCODE(130)
+INTR_NOERRCODE(131)
+INTR_NOERRCODE(132)
+INTR_NOERRCODE(133)
+INTR_NOERRCODE(134)
+INTR_NOERRCODE(135)
+INTR_NOERRCODE(136)
+INTR_NOERRCODE(137)
+INTR_NOERRCODE(138)
+INTR_NOERRCODE(139)
+INTR_NOERRCODE(140)
+INTR_NOERRCODE(141)
+INTR_NOERRCODE(142)
+INTR_NOERRCODE(143)
+INTR_NOERRCODE(144)
+INTR_NOERRCODE(145)
+INTR_NOERRCODE(146)
+INTR_NOERRCODE(147)
+INTR_NOERRCODE(148)
+INTR_NOERRCODE(149)
+INTR_NOERRCODE(150)
+INTR_NOERRCODE(151)
+INTR_NOERRCODE(152)
+INTR_NOERRCODE(153)
+INTR_NOERRCODE(154)
+INTR_NOERRCODE(155)
+INTR_NOERRCODE(156)
+INTR_NOERRCODE(157)
+INTR_NOERRCODE(158)
+INTR_NOERRCODE(159)
+INTR_NOERRCODE(160)
+INTR_NOERRCODE(161)
+INTR_NOERRCODE(162)
+INTR_NOERRCODE(163)
+INTR_NOERRCODE(164)
+INTR_NOERRCODE(165)
+INTR_NOERRCODE(166)
+INTR_NOERRCODE(167)
+INTR_NOERRCODE(168)
+INTR_NOERRCODE(169)
+INTR_NOERRCODE(170)
+INTR_NOERRCODE(171)
+INTR_NOERRCODE(172)
+INTR_NOERRCODE(173)
+INTR_NOERRCODE(174)
+INTR_NOERRCODE(175)
+INTR_NOERRCODE(176)
+INTR_NOERRCODE(177)
+INTR_NOERRCODE(178)
+INTR_NOERRCODE(179)
+INTR_NOERRCODE(180)
+INTR_NOERRCODE(181)
+INTR_NOERRCODE(182)
+INTR_NOERRCODE(183)
+INTR_NOERRCODE(184)
+INTR_NOERRCODE(185)
+INTR_NOERRCODE(186)
+INTR_NOERRCODE(187)
+INTR_NOERRCODE(188)
+INTR_NOERRCODE(189)
+INTR_NOERRCODE(190)
+INTR_NOERRCODE(191)
+INTR_NOERRCODE(192)
+INTR_NOERRCODE(193)
+INTR_NOERRCODE(194)
+INTR_NOERRCODE(195)
+INTR_NOERRCODE(196)
+INTR_NOERRCODE(197)
+INTR_NOERRCODE(198)
+INTR_NOERRCODE(199)
+INTR_NOERRCODE(200)
+INTR_NOERRCODE(201)
+INTR_NOERRCODE(202)
+INTR_NOERRCODE(203)
+INTR_NOERRCODE(204)
+INTR_NOERRCODE(205)
+INTR_NOERRCODE(206)
+INTR_NOERRCODE(207)
+INTR_NOERRCODE(208)
+INTR_NOERRCODE(209)
+INTR_NOERRCODE(210)
+INTR_NOERRCODE(211)
+INTR_NOERRCODE(212)
+INTR_NOERRCODE(213)
+INTR_NOERRCODE(214)
+INTR_NOERRCODE(215)
+INTR_NOERRCODE(216)
+INTR_NOERRCODE(217)
+INTR_NOERRCODE(218)
+INTR_NOERRCODE(219)
+INTR_NOERRCODE(220)
+INTR_NOERRCODE(221)
+INTR_NOERRCODE(222)
+INTR_NOERRCODE(223)
+INTR_NOERRCODE(224)
+INTR_NOERRCODE(225)
+INTR_NOERRCODE(226)
+INTR_NOERRCODE(227)
+INTR_NOERRCODE(228)
+INTR_NOERRCODE(229)
+INTR_NOERRCODE(230)
+INTR_NOERRCODE(231)
+INTR_NOERRCODE(232)
+INTR_NOERRCODE(233)
+INTR_NOERRCODE(234)
+INTR_NOERRCODE(235)
+INTR_NOERRCODE(236)
+INTR_NOERRCODE(237)
+INTR_NOERRCODE(238)
+INTR_NOERRCODE(239)
+INTR_NOERRCODE(240)
+INTR_NOERRCODE(241)
+INTR_NOERRCODE(242)
+INTR_NOERRCODE(243)
+INTR_NOERRCODE(244)
+INTR_NOERRCODE(245)
+INTR_NOERRCODE(246)
+INTR_NOERRCODE(247)
+INTR_NOERRCODE(248)
+INTR_NOERRCODE(249)
+INTR_NOERRCODE(250)
+INTR_NOERRCODE(251)
+INTR_NOERRCODE(252)
+INTR_NOERRCODE(253)
+INTR_NOERRCODE(254)
+INTR_NOERRCODE(255)
+
+typedef struct intr_desc
+{
+ uint16_t offset1;
+ uint16_t selector;
+ uint8_t ist;
+ uint8_t attr; // type and attributes
+ uint16_t offset2; // offset bits 16..31
+ uint32_t offset3; // offset bits 32..63
+ uint32_t zero;
+} packed intr_desc_t;
+
+typedef struct intr_info
+{
+ uint16_t size;
+ uintptr_t base;
+} packed intr_info_t;
+
+static intr_desc_t intr_table[MAX_INTERRUPTS];
+static intr_handler_t intr_handlers[MAX_INTERRUPTS];
+static int32_t intr_mappings[MAX_INTERRUPTS];
+
+intr_info_t intr_data;
+
+/* This variable is updated when an interrupt occurs to
+ * point to the saved registers of the interrupted context.
+ * When it is non-NULL the processor is in an interrupt
+ * context, otherwise it is in a non-interrupt process.
+ * This variable is maintained for easy reference by
+ * debuggers. */
+static regs_t *_intr_regs CORE_SPECIFIC_DATA;
+
+inline uint8_t intr_setipl(uint8_t ipl)
+{
+ uint8_t oldipl = apic_getipl();
+ apic_setipl(ipl);
+ return oldipl;
+}
+
+inline uint8_t intr_getipl() { return apic_getipl(); }
+
+static __attribute__((used)) void interrupt_handler(regs_t regs)
+{
+ intr_handler_t handler = intr_handlers[regs.r_intr];
+ _intr_regs = &regs;
+ if (handler)
+ {
+ if ((regs.r_cs & 0x3) == 0x3)
+ {
+ // KASSERT(preemption_enabled()); TODO figure out why
+ // this sometimes fails!!
+ }
+ if (!handler(&regs))
+ apic_eoi();
+ }
+ else
+ {
+ panic("Unhandled interrupt 0x%x\n", (int)regs.r_intr);
+ }
+ _intr_regs = NULL;
+}
+
+int32_t intr_map(uint16_t irq, uint8_t intr)
+{
+ KASSERT(INTR_SPURIOUS != intr);
+
+ int32_t oldirq = intr_mappings[intr];
+ intr_mappings[intr] = irq;
+ apic_setredir(irq, intr);
+ return oldirq;
+}
+
+intr_handler_t intr_register(uint8_t intr, intr_handler_t handler)
+{
+ intr_handler_t old = intr_handlers[intr];
+ intr_handlers[intr] = handler;
+ return old;
+}
+
+// lol
+void dump_registers(regs_t *regs)
+{
+ dbg(DBG_PRINT,
+ "Registers:\nintr=0x%08lx\nerr=0x%08lx\nrip=0x%08lx\ncs=0x%"
+ "08lx\nrflags=0x%08lx\nrsp=0x%08lx\n"
+ "ss=0x%08lx\nrdi=0x%08lx\nrsi=0x%08lx\nrdx=0x%08lx\nrcx=0x%08lx\nrax="
+ "0x%08lx\nr8=0x%08lx\n"
+ "r9=0x%08lx\nr10=0x%08lx\nr11=0x%08lx\nrbx=0x%08lx\nrbp=0x%08lx\nr12="
+ "0x%08lx\nr13=0x%08lx\n"
+ "r14=0x%08lx\nr15=0x%08lx\n",
+ regs->r_intr, regs->r_err, regs->r_rip, regs->r_cs, regs->r_rflags,
+ regs->r_rsp, regs->r_ss, regs->r_rdi, regs->r_rsi, regs->r_rdx,
+ regs->r_rcx, regs->r_rax, regs->r_r8, regs->r_r9, regs->r_r10,
+ regs->r_r11, regs->r_rbx, regs->r_rbp, regs->r_r12, regs->r_r13,
+ regs->r_r14, regs->r_r15);
+}
+
+static long __intr_gpf_handler(regs_t *regs)
+{
+ // check if we're in userland
+ if ((regs->r_cs & 0x3) == 0x3)
+ {
+ // most likely accessed a non-canonical address
+ do_exit(EFAULT);
+ }
+ else
+ {
+ dump_registers(regs);
+ panic("\n\nTriggered a General Protection Fault\n");
+ }
+ return 0;
+}
+
+static long __intr_divide_by_zero_handler(regs_t *regs)
+{
+ // check if we're in userland
+ if ((regs->r_cs & 0x3) == 0x3)
+ {
+ do_exit(EPERM);
+ }
+ else
+ {
+ dump_registers(regs);
+ panic("\n\nTriggered a Divide by Zero exception\n");
+ }
+ return 0;
+}
+
+static long __intr_inval_opcode_handler(regs_t *regs)
+{
+ // check if we're in userland
+ if ((regs->r_cs & 0x3) == 0x3)
+ {
+ do_exit(EPERM);
+ }
+ else
+ {
+ dump_registers(regs);
+ panic("\n\nTriggered a General Protection Fault!\n");
+ }
+ return 0;
+}
+
+static long __intr_spurious(regs_t *regs)
+{
+ dbg(DBG_CORE, "ignoring spurious interrupt\n");
+ return 0;
+}
+
+static void __intr_set_entry(uint8_t isr, uintptr_t addr, uint8_t seg,
+ uint8_t flags)
+{
+ // [+] TODO MAGIC NUMBERS
+ intr_table[isr].offset1 = (uint16_t)((addr)&0xffff);
+ intr_table[isr].offset2 = (uint16_t)(((addr) >> 16) & 0xffff);
+ intr_table[isr].offset3 = (uint32_t)((addr) >> 32);
+ intr_table[isr].zero = 0;
+ intr_table[isr].attr = flags;
+ intr_table[isr].selector = seg;
+ intr_table[isr].ist = 0;
+}
+
+static void __intr_set_entries();
+
+void intr_init()
+{
+ static long inited = 0;
+ intr_info_t *data = &intr_data;
+
+ if (!inited)
+ {
+ // global interrupt table
+ inited = 1;
+
+ // initialize intr_data
+ data->size = sizeof(intr_desc_t) * MAX_INTERRUPTS - 1;
+ data->base = (uintptr_t)intr_table;
+
+ memset(intr_handlers, 0, sizeof(intr_handlers));
+ memset(intr_mappings, -1, sizeof(intr_mappings));
+
+ __intr_set_entries();
+ }
+ __asm__("lidt (%0)" ::"p"(data));
+
+ intr_register(INTR_SPURIOUS, __intr_spurious);
+ intr_register(INTR_DIVIDE_BY_ZERO, __intr_divide_by_zero_handler);
+ intr_register(INTR_GPF, __intr_gpf_handler);
+ intr_register(INTR_INVALID_OPCODE, __intr_inval_opcode_handler);
+}
+
+static void __intr_set_entries()
+{
+ __intr_set_entry(0, (uintptr_t)&INTR(0), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(1, (uintptr_t)&INTR(1), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(2, (uintptr_t)&INTR(2), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(3, (uintptr_t)&INTR(3), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(4, (uintptr_t)&INTR(4), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(5, (uintptr_t)&INTR(5), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(6, (uintptr_t)&INTR(6), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(7, (uintptr_t)&INTR(7), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(8, (uintptr_t)&INTR(8), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(9, (uintptr_t)&INTR(9), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(10, (uintptr_t)&INTR(10), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(11, (uintptr_t)&INTR(11), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(12, (uintptr_t)&INTR(12), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(13, (uintptr_t)&INTR(13), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(14, (uintptr_t)&INTR(14), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(15, (uintptr_t)&INTR(15), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(16, (uintptr_t)&INTR(16), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(17, (uintptr_t)&INTR(17), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(18, (uintptr_t)&INTR(18), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(19, (uintptr_t)&INTR(19), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(20, (uintptr_t)&INTR(20), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(21, (uintptr_t)&INTR(21), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(22, (uintptr_t)&INTR(22), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(23, (uintptr_t)&INTR(23), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(24, (uintptr_t)&INTR(24), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(25, (uintptr_t)&INTR(25), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(26, (uintptr_t)&INTR(26), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(27, (uintptr_t)&INTR(27), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(28, (uintptr_t)&INTR(28), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(29, (uintptr_t)&INTR(29), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(30, (uintptr_t)&INTR(30), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(31, (uintptr_t)&INTR(31), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(32, (uintptr_t)&INTR(32), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(33, (uintptr_t)&INTR(33), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(34, (uintptr_t)&INTR(34), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(35, (uintptr_t)&INTR(35), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(36, (uintptr_t)&INTR(36), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(37, (uintptr_t)&INTR(37), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(38, (uintptr_t)&INTR(38), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(39, (uintptr_t)&INTR(39), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(40, (uintptr_t)&INTR(40), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(41, (uintptr_t)&INTR(41), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(42, (uintptr_t)&INTR(42), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(43, (uintptr_t)&INTR(43), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(44, (uintptr_t)&INTR(44), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(45, (uintptr_t)&INTR(45), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ /* BEWARE - this is the interrupt table entry for userland syscalls. It
+ * differs from all the others. */
+ __intr_set_entry(
+ 46, (uintptr_t)&INTR(46), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_TRAP | IDT_DESC_RING3);
+ /* */
+ __intr_set_entry(47, (uintptr_t)&INTR(47), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(48, (uintptr_t)&INTR(48), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(49, (uintptr_t)&INTR(49), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(50, (uintptr_t)&INTR(50), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(51, (uintptr_t)&INTR(51), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(52, (uintptr_t)&INTR(52), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(53, (uintptr_t)&INTR(53), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(54, (uintptr_t)&INTR(54), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(55, (uintptr_t)&INTR(55), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(56, (uintptr_t)&INTR(56), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(57, (uintptr_t)&INTR(57), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(58, (uintptr_t)&INTR(58), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(59, (uintptr_t)&INTR(59), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(60, (uintptr_t)&INTR(60), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(61, (uintptr_t)&INTR(61), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(62, (uintptr_t)&INTR(62), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(63, (uintptr_t)&INTR(63), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(64, (uintptr_t)&INTR(64), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(65, (uintptr_t)&INTR(65), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(66, (uintptr_t)&INTR(66), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(67, (uintptr_t)&INTR(67), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(68, (uintptr_t)&INTR(68), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(69, (uintptr_t)&INTR(69), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(60, (uintptr_t)&INTR(70), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(71, (uintptr_t)&INTR(71), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(72, (uintptr_t)&INTR(72), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(73, (uintptr_t)&INTR(73), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(74, (uintptr_t)&INTR(74), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(75, (uintptr_t)&INTR(75), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(76, (uintptr_t)&INTR(76), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(77, (uintptr_t)&INTR(77), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(78, (uintptr_t)&INTR(78), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(79, (uintptr_t)&INTR(79), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(70, (uintptr_t)&INTR(80), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(81, (uintptr_t)&INTR(81), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(82, (uintptr_t)&INTR(82), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(83, (uintptr_t)&INTR(83), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(84, (uintptr_t)&INTR(84), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(85, (uintptr_t)&INTR(85), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(86, (uintptr_t)&INTR(86), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(87, (uintptr_t)&INTR(87), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(88, (uintptr_t)&INTR(88), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(89, (uintptr_t)&INTR(89), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(90, (uintptr_t)&INTR(90), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(91, (uintptr_t)&INTR(91), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(92, (uintptr_t)&INTR(92), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(93, (uintptr_t)&INTR(93), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(94, (uintptr_t)&INTR(94), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(95, (uintptr_t)&INTR(95), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(96, (uintptr_t)&INTR(96), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(97, (uintptr_t)&INTR(97), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(98, (uintptr_t)&INTR(98), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(99, (uintptr_t)&INTR(99), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(100, (uintptr_t)&INTR(100), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(101, (uintptr_t)&INTR(101), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(102, (uintptr_t)&INTR(102), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(103, (uintptr_t)&INTR(103), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(104, (uintptr_t)&INTR(104), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(105, (uintptr_t)&INTR(105), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(106, (uintptr_t)&INTR(106), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(107, (uintptr_t)&INTR(107), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(108, (uintptr_t)&INTR(108), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(109, (uintptr_t)&INTR(109), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(110, (uintptr_t)&INTR(110), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(111, (uintptr_t)&INTR(111), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(112, (uintptr_t)&INTR(112), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(113, (uintptr_t)&INTR(113), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(114, (uintptr_t)&INTR(114), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(115, (uintptr_t)&INTR(115), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(116, (uintptr_t)&INTR(116), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(117, (uintptr_t)&INTR(117), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(118, (uintptr_t)&INTR(118), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(119, (uintptr_t)&INTR(119), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(120, (uintptr_t)&INTR(120), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(121, (uintptr_t)&INTR(121), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(122, (uintptr_t)&INTR(122), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(123, (uintptr_t)&INTR(123), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(124, (uintptr_t)&INTR(124), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(125, (uintptr_t)&INTR(125), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(126, (uintptr_t)&INTR(126), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(127, (uintptr_t)&INTR(127), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(128, (uintptr_t)&INTR(128), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(129, (uintptr_t)&INTR(129), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(130, (uintptr_t)&INTR(130), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(131, (uintptr_t)&INTR(131), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(132, (uintptr_t)&INTR(132), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(133, (uintptr_t)&INTR(133), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(134, (uintptr_t)&INTR(134), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(135, (uintptr_t)&INTR(135), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(136, (uintptr_t)&INTR(136), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(137, (uintptr_t)&INTR(137), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(138, (uintptr_t)&INTR(138), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(139, (uintptr_t)&INTR(139), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(140, (uintptr_t)&INTR(140), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(141, (uintptr_t)&INTR(141), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(142, (uintptr_t)&INTR(142), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(143, (uintptr_t)&INTR(143), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(144, (uintptr_t)&INTR(144), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(145, (uintptr_t)&INTR(145), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(146, (uintptr_t)&INTR(146), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(147, (uintptr_t)&INTR(147), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(148, (uintptr_t)&INTR(148), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(149, (uintptr_t)&INTR(149), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(150, (uintptr_t)&INTR(150), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(151, (uintptr_t)&INTR(151), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(152, (uintptr_t)&INTR(152), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(153, (uintptr_t)&INTR(153), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(154, (uintptr_t)&INTR(154), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(155, (uintptr_t)&INTR(155), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(156, (uintptr_t)&INTR(156), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(157, (uintptr_t)&INTR(157), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(158, (uintptr_t)&INTR(158), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(159, (uintptr_t)&INTR(159), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(160, (uintptr_t)&INTR(160), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(161, (uintptr_t)&INTR(161), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(162, (uintptr_t)&INTR(162), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(163, (uintptr_t)&INTR(163), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(164, (uintptr_t)&INTR(164), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(165, (uintptr_t)&INTR(165), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(166, (uintptr_t)&INTR(166), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(167, (uintptr_t)&INTR(167), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(168, (uintptr_t)&INTR(168), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(169, (uintptr_t)&INTR(169), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(160, (uintptr_t)&INTR(170), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(171, (uintptr_t)&INTR(171), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(172, (uintptr_t)&INTR(172), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(173, (uintptr_t)&INTR(173), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(174, (uintptr_t)&INTR(174), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(175, (uintptr_t)&INTR(175), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(176, (uintptr_t)&INTR(176), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(177, (uintptr_t)&INTR(177), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(178, (uintptr_t)&INTR(178), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(179, (uintptr_t)&INTR(179), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(170, (uintptr_t)&INTR(180), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(181, (uintptr_t)&INTR(181), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(182, (uintptr_t)&INTR(182), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(183, (uintptr_t)&INTR(183), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(184, (uintptr_t)&INTR(184), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(185, (uintptr_t)&INTR(185), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(186, (uintptr_t)&INTR(186), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(187, (uintptr_t)&INTR(187), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(188, (uintptr_t)&INTR(188), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(189, (uintptr_t)&INTR(189), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(190, (uintptr_t)&INTR(190), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(191, (uintptr_t)&INTR(191), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(192, (uintptr_t)&INTR(192), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(193, (uintptr_t)&INTR(193), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(194, (uintptr_t)&INTR(194), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(195, (uintptr_t)&INTR(195), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(196, (uintptr_t)&INTR(196), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(197, (uintptr_t)&INTR(197), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(198, (uintptr_t)&INTR(198), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(199, (uintptr_t)&INTR(199), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(200, (uintptr_t)&INTR(200), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(201, (uintptr_t)&INTR(201), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(202, (uintptr_t)&INTR(202), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(203, (uintptr_t)&INTR(203), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(204, (uintptr_t)&INTR(204), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(205, (uintptr_t)&INTR(205), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(206, (uintptr_t)&INTR(206), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(207, (uintptr_t)&INTR(207), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(208, (uintptr_t)&INTR(208), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(209, (uintptr_t)&INTR(209), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(210, (uintptr_t)&INTR(210), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(211, (uintptr_t)&INTR(211), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(212, (uintptr_t)&INTR(212), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(213, (uintptr_t)&INTR(213), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(214, (uintptr_t)&INTR(214), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(215, (uintptr_t)&INTR(215), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(216, (uintptr_t)&INTR(216), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(217, (uintptr_t)&INTR(217), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(218, (uintptr_t)&INTR(218), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(219, (uintptr_t)&INTR(219), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(220, (uintptr_t)&INTR(220), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(221, (uintptr_t)&INTR(221), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(222, (uintptr_t)&INTR(222), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(223, (uintptr_t)&INTR(223), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(224, (uintptr_t)&INTR(224), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(225, (uintptr_t)&INTR(225), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(226, (uintptr_t)&INTR(226), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(227, (uintptr_t)&INTR(227), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(228, (uintptr_t)&INTR(228), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(229, (uintptr_t)&INTR(229), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(230, (uintptr_t)&INTR(230), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(231, (uintptr_t)&INTR(231), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(232, (uintptr_t)&INTR(232), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(233, (uintptr_t)&INTR(233), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(234, (uintptr_t)&INTR(234), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(235, (uintptr_t)&INTR(235), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(236, (uintptr_t)&INTR(236), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(237, (uintptr_t)&INTR(237), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(238, (uintptr_t)&INTR(238), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(239, (uintptr_t)&INTR(239), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(240, (uintptr_t)&INTR(240), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(241, (uintptr_t)&INTR(241), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(242, (uintptr_t)&INTR(242), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(243, (uintptr_t)&INTR(243), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(244, (uintptr_t)&INTR(244), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(245, (uintptr_t)&INTR(245), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(246, (uintptr_t)&INTR(246), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(247, (uintptr_t)&INTR(247), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(248, (uintptr_t)&INTR(248), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(249, (uintptr_t)&INTR(249), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(250, (uintptr_t)&INTR(250), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(251, (uintptr_t)&INTR(251), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(252, (uintptr_t)&INTR(252), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(253, (uintptr_t)&INTR(253), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(254, (uintptr_t)&INTR(254), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+ __intr_set_entry(255, (uintptr_t)&INTR(255), GDT_KERNEL_TEXT,
+ IDT_DESC_PRESENT | IDT_DESC_BIT32 | IDT_DESC_RING0);
+}
diff --git a/kernel/main/kmain.c b/kernel/main/kmain.c
new file mode 100644
index 0000000..6807328
--- /dev/null
+++ b/kernel/main/kmain.c
@@ -0,0 +1,200 @@
+#include "errno.h"
+#include "globals.h"
+#include "types.h"
+#include <api/exec.h>
+#include <drivers/screen.h>
+#include <drivers/tty/tty.h>
+#include <drivers/tty/vterminal.h>
+#include <main/io.h>
+#include <mm/mm.h>
+#include <mm/slab.h>
+#include <test/kshell/kshell.h>
+#include <util/time.h>
+#include <vm/anon.h>
+#include <vm/shadow.h>
+
+#include "util/debug.h"
+#include "util/gdb.h"
+#include "util/printf.h"
+#include "util/string.h"
+
+#include "main/acpi.h"
+#include "main/apic.h"
+#include "main/inits.h"
+
+#include "drivers/dev.h"
+#include "drivers/pcie.h"
+
+#include "api/syscall.h"
+
+#include "fs/fcntl.h"
+#include "fs/vfs.h"
+#include "fs/vfs_syscall.h"
+#include "fs/vnode.h"
+
+#include "test/driverstest.h"
+
+GDB_DEFINE_HOOK(boot)
+
+GDB_DEFINE_HOOK(initialized)
+
+GDB_DEFINE_HOOK(shutdown)
+
+static void initproc_start();
+
+typedef void (*init_func_t)();
+static init_func_t init_funcs[] = {
+ dbg_init,
+ intr_init,
+ page_init,
+ pt_init,
+ acpi_init,
+ apic_init,
+ core_init,
+ slab_init,
+ pframe_init,
+ pci_init,
+ vga_init,
+#ifdef __VM__
+ anon_init,
+ shadow_init,
+#endif
+ vmmap_init,
+ proc_init,
+ kthread_init,
+#ifdef __DRIVERS__
+ chardev_init,
+ blockdev_init,
+#endif
+ kshell_init,
+ file_init,
+ pipe_init,
+ syscall_init,
+ elf64_init,
+
+ proc_idleproc_init,
+};
+
+/*
+ * Call the init functions (in order!), then run the init process
+ * (initproc_start)
+ */
+void kmain()
+{
+ GDB_CALL_HOOK(boot);
+
+ for (size_t i = 0; i < sizeof(init_funcs) / sizeof(init_funcs[0]); i++)
+ init_funcs[i]();
+
+ initproc_start();
+ panic("\nReturned to kmain()\n");
+}
+
+/*
+ * Make:
+ * 1) /dev/null
+ * 2) /dev/zero
+ * 3) /dev/ttyX for 0 <= X < __NTERMS__
+ * 4) /dev/hdaX for 0 <= X < __NDISKS__
+ */
+static void make_devices()
+{
+ long status = do_mkdir("/dev");
+ KASSERT(!status || status == -EEXIST);
+
+ status = do_mknod("/dev/null", S_IFCHR, MEM_NULL_DEVID);
+ KASSERT(!status || status == -EEXIST);
+ status = do_mknod("/dev/zero", S_IFCHR, MEM_ZERO_DEVID);
+ KASSERT(!status || status == -EEXIST);
+
+ char path[32] = {0};
+ for (long i = 0; i < __NTERMS__; i++)
+ {
+ snprintf(path, sizeof(path), "/dev/tty%ld", i);
+ dbg(DBG_INIT, "Creating tty mknod with path %s\n", path);
+ status = do_mknod(path, S_IFCHR, MKDEVID(TTY_MAJOR, i));
+ KASSERT(!status || status == -EEXIST);
+ }
+
+ for (long i = 0; i < __NDISKS__; i++)
+ {
+ snprintf(path, sizeof(path), "/dev/hda%ld", i);
+ dbg(DBG_INIT, "Creating disk mknod with path %s\n", path);
+ status = do_mknod(path, S_IFBLK, MKDEVID(DISK_MAJOR, i));
+ KASSERT(!status || status == -EEXIST);
+ }
+}
+
+/*
+ * The function executed by the init process. Finish up all initialization now
+ * that we have a proper thread context.
+ *
+ * This function will require edits over the course of the project:
+ *
+ * - Before finishing drivers, this is where your tests lie. You can, however,
+ * have them in a separate test function which can even be in a separate file
+ * (see handout).
+ *
+ * - After finishing drivers but before starting VM, you should start __NTERMS__
+ * processes running kshells (see kernel/test/kshell/kshell.c, specifically
+ * kshell_proc_run). Testing here amounts to defining a new kshell command
+ * that runs your tests.
+ *
+ * - During and after VM, you should use kernel_execve when starting, you
+ * will probably want to kernel_execve the program you wish to test directly.
+ * Eventually, you will want to kernel_execve "/sbin/init" and run your
+ * tests from the userland shell (by typing in test commands)
+ *
+ * Note: The init process should wait on all of its children to finish before
+ * returning from this function (at which point the system will shut down).
+ */
+static void *initproc_run(long arg1, void *arg2)
+{
+#ifdef __VFS__
+ dbg(DBG_INIT, "Initializing VFS...\n");
+ vfs_init();
+ make_devices();
+#endif
+
+ NOT_YET_IMPLEMENTED("PROCS: GDB_DEFINE_HOOK");
+
+ return NULL;
+}
+
+/*
+ * Sets up the initial process and prepares it to run.
+ *
+ * Hints:
+ * Use proc_create() to create the initial process.
+ * Use kthread_create() to create the initial process's only thread.
+ * Make sure the thread is set up to start running initproc_run() (values for
+ * arg1 and arg2 do not matter, they can be 0 and NULL).
+ * Use sched_make_runnable() to make the thread runnable.
+ * Use context_make_active() with the context of the current core (curcore)
+ * to start the scheduler.
+ */
+void initproc_start()
+{
+ NOT_YET_IMPLEMENTED("PROCS: GDB_DEFINE_HOOK");
+}
+
+void initproc_finish()
+{
+#ifdef __VFS__
+ if (vfs_shutdown())
+ panic("vfs shutdown FAILED!!\n");
+
+#endif
+
+#ifdef __DRIVERS__
+ screen_print_shutdown();
+#endif
+
+ /* sleep forever */
+ while (1)
+ {
+ __asm__ volatile("cli; hlt;");
+ }
+
+ panic("should not get here");
+}
diff --git a/kernel/main/smp.c b/kernel/main/smp.c
new file mode 100644
index 0000000..fb85469
--- /dev/null
+++ b/kernel/main/smp.c
@@ -0,0 +1,138 @@
+#include "globals.h"
+#include "types.h"
+#include <main/gdt.h>
+
+#include "main/apic.h"
+#include "main/inits.h"
+
+#include "mm/tlb.h"
+
+#include "util/string.h"
+#include "util/time.h"
+
+static long smp_processor_count;
+
+extern uintptr_t smp_initialization_start;
+extern uintptr_t smp_initialization_end;
+#define smp_initialization_start ((uintptr_t)(&smp_initialization_start))
+#define smp_initialization_end ((uintptr_t)(&smp_initialization_end))
+#define smp_initialization_size \
+ (smp_initialization_end - smp_initialization_start)
+
+static void smp_start_processor(uint8_t apic_id);
+static long smp_stop_processor(regs_t *regs);
+
+extern void *csd_start;
+extern void *csd_end;
+#define CSD_START ((uintptr_t)&csd_start)
+#define CSD_END ((uintptr_t)&csd_end)
+#define CSD_PAGES (uintptr_t)((CSD_END - CSD_START) >> PAGE_SHIFT)
+
+core_t curcore CORE_SPECIFIC_DATA;
+uintptr_t csd_vaddr_table[MAX_LAPICS] = {NULL};
+
+void map_in_core_specific_data(pml4_t *pml4)
+{
+ pt_map_range(pml4, curcore.kc_csdpaddr, CSD_START, CSD_END,
+ PT_PRESENT | PT_WRITE, PT_PRESENT | PT_WRITE);
+ uintptr_t mapped_paddr = pt_virt_to_phys_helper(pml4, (uintptr_t)&curcore);
+ uintptr_t expected_paddr =
+ (uintptr_t)GET_CSD(curcore.kc_id, core_t, curcore) - PHYS_OFFSET;
+ uintptr_t expected_paddr2 =
+ pt_virt_to_phys_helper(pt_get(), (uintptr_t)&curcore);
+ KASSERT(mapped_paddr == expected_paddr);
+ KASSERT(expected_paddr == expected_paddr2);
+}
+
+long is_core_specific_data(void *addr)
+{
+ return (uintptr_t)addr >= CSD_START && (uintptr_t)addr < CSD_END;
+}
+
+void core_init()
+{
+ // order of operations are pretty important here
+ pt_init();
+ pt_set(pt_create());
+
+ uintptr_t csd_paddr = (uintptr_t)page_alloc_n(CSD_PAGES);
+ if (!csd_paddr)
+ panic("not enough memory for core-specific data!");
+ csd_vaddr_table[apic_current_id()] =
+ csd_paddr; // still in PHYSMAP region; still a VMA
+ csd_paddr -= PHYS_OFFSET;
+
+ dbg(DBG_CORE, "mapping in core specific data to 0x%p\n", (void *)csd_paddr);
+ pt_map_range(pt_get(), csd_paddr, CSD_START, CSD_END, PT_PRESENT | PT_WRITE,
+ PT_PRESENT | PT_WRITE);
+ tlb_flush_all();
+
+ memset((void *)CSD_START, 0, CSD_END - CSD_START);
+
+ curcore.kc_id = apic_current_id();
+ curcore.kc_queue = NULL;
+ curcore.kc_csdpaddr = csd_paddr;
+
+ intr_init();
+ gdt_init();
+
+ apic_enable();
+ time_init();
+ sched_init();
+
+ void *stack = page_alloc();
+ KASSERT(stack != NULL);
+
+ context_setup_raw(&curcore.kc_ctx, core_switch, stack, PAGE_SIZE, pt_get());
+}
+
+void __attribute__((used)) smp_processor_entry()
+{
+ core_init();
+ dbg_force(DBG_CORE, "started C%ld!\n", curcore.kc_id);
+ smp_processor_count++;
+
+ KASSERT(!intr_enabled());
+ preemption_disable();
+ proc_idleproc_init();
+ context_make_active(&curcore.kc_ctx);
+}
+
+/*
+ * Prepare for SMP by copying the real-mode trampoline code into the
+ * first 1mb of memory.
+ */
+void smp_init()
+{
+ NOT_YET_IMPLEMENTED("SMP: ***none***");
+}
+
+// Intel Vol. 3A 10-11, 10.4.7.3
+static void smp_start_processor(uint8_t apic_id)
+{
+ // TODO: not necessarily true that apic_id == processor_id
+ dbg_force(DBG_CORE, "Booting C%d\n", apic_id);
+
+ memcpy((void *)PHYS_OFFSET, (void *)smp_initialization_start,
+ smp_initialization_size);
+
+ // First, send a INIT IPI
+
+ long prev_count = smp_processor_count;
+ apic_start_processor(apic_id, 0);
+
+ while (smp_processor_count == prev_count)
+ ;
+}
+
+static long smp_stop_processor(regs_t *regs)
+{
+ char buf[2048];
+ time_stats(buf, sizeof(buf));
+
+ dbg_force(DBG_CORE, "\n%s\nhalted cleanly!\n\n", buf);
+
+ __asm__ volatile("cli; hlt;");
+
+ return 0;
+}
diff --git a/kernel/main/smp_trampoline.S b/kernel/main/smp_trampoline.S
new file mode 100644
index 0000000..9273f0f
--- /dev/null
+++ b/kernel/main/smp_trampoline.S
@@ -0,0 +1,81 @@
+#define CR0_PG 0x80000000
+#define CR0_PE 0x00000001
+
+#define CR4_PAE 0x00000020
+#define CR4_PGE 0x00000080
+
+#define PHYSADDR(x) (x - smp_initialization_start)
+
+# NOTE: THIS CODE REQUIRES THAT IT BE PLACED STARTING AT PHYSICAL ADDRESS 0x0
+
+.file "smp_trampoline.S"
+.global smp_initialization_start, smp_initialization_end
+
+smp_initialization_start:
+
+/* When we initialize a processor, it starts in 16-bit real mode */
+.code16
+.align 0x1000
+smp_processor_init:
+ cli
+
+ // enable PAE
+ mov $(CR4_PAE | CR4_PGE), %eax
+ mov %eax, %cr4
+
+ mov $PHYSADDR(pml4), %eax
+ mov %eax, %cr3
+
+ // enter long mode
+ mov $0xC0000080, %ecx
+ rdmsr
+ or $0x100, %eax
+ wrmsr
+
+ lgdt PHYSADDR(GDTPointer)
+
+ // Enable paging AND protection simultaneously
+ movl %cr0, %eax
+ or $(CR0_PG | CR0_PE), %eax
+ movl %eax, %cr0
+
+ ljmp $0x8, $PHYSADDR(smp_trampoline)
+
+.code64
+smp_trampoline:
+ movabsq $(0xffff880000000000 + PHYSADDR(stack_pointer)), %rsp
+ xor %rbp, %rbp
+ movabsq $smp_processor_entry, %rax
+ call *%rax
+
+
+.align 16
+GDT64:
+ GDTNull:
+ .quad 0
+ GDTKernelCode:
+ // base = 0x0, limit = 0x0
+ // flags: present, ring 0, executable, readable, 64bit
+ .word 0, 0
+ .byte 0, 0x9a, 0x20, 0
+ GDTEnd:
+ GDTPointer:
+ .word GDTEnd - GDT64 - 1 // size of gdt - 1
+ .long PHYSADDR(GDT64) // pointer to gdt
+
+.align 0x1000
+pml4: // maps first 1GB of RAM to both 0x0000000000000000 and 0xffff800000000000
+ .quad PHYSADDR(pdpt) + 3
+ .fill 255,8,0
+ .quad PHYSADDR(pdpt) + 3
+ .fill 15,8,0
+ .quad PHYSADDR(pdpt) + 3
+ .fill 239,8,0
+pdpt:
+ .quad 0x0000000000000083
+ .fill 511,8,0
+
+.skip 0x1000
+stack_pointer:
+
+smp_initialization_end: