diff options
Diffstat (limited to 'kernel/main')
| -rw-r--r-- | kernel/main/acpi.c | 161 | ||||
| -rw-r--r-- | kernel/main/apic.c | 648 | ||||
| -rw-r--r-- | kernel/main/gdt.c | 129 | ||||
| -rw-r--r-- | kernel/main/gdt.gdb | 3 | ||||
| -rw-r--r-- | kernel/main/interrupt.c | 1077 | ||||
| -rw-r--r-- | kernel/main/kmain.c | 200 | ||||
| -rw-r--r-- | kernel/main/smp.c | 138 | ||||
| -rw-r--r-- | kernel/main/smp_trampoline.S | 81 |
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 = ®s; + if (handler) + { + if ((regs.r_cs & 0x3) == 0x3) + { + // KASSERT(preemption_enabled()); TODO figure out why + // this sometimes fails!! + } + if (!handler(®s)) + 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: |
