diff --git a/src/modules/main/boot.s b/src/modules/main/boot.s index 6df8f28..be3ff8a 100644 --- a/src/modules/main/boot.s +++ b/src/modules/main/boot.s @@ -17,6 +17,8 @@ section .text align 16 global _start:function (_start.end - _start) _start: + cli + extern kernel_main call kernel_main @@ -26,3 +28,13 @@ _start: hlt jmp .hang .end: + +global interrupts_enable +interrupts_enable: + sti + ret + +global interrupts_disable +interrupts_disable: + cli + ret diff --git a/src/modules/main/device_manager.cpp b/src/modules/main/device_manager.cpp new file mode 100644 index 0000000..428306f --- /dev/null +++ b/src/modules/main/device_manager.cpp @@ -0,0 +1,68 @@ +#include +#include + +#include "device_manager.h" +#include "console.h" +#include "util.h" + +static const char expected_signature[] = "RSD PTR "; + +struct Acpi10RSDPDescriptor +{ + char signature[8]; + uint8_t checksum; + char oem_id[6]; + uint8_t revision; + uint32_t rsdt_address; +} __attribute__ ((packed)); + +struct Acpi20RSDPDescriptor +{ + char signature[8]; + uint8_t checksum10; + char oem_id[6]; + uint8_t revision; + uint32_t rsdt_address; + + uint32_t length; + uint64_t xsdt_address; + uint8_t checksum20; + uint8_t reserved[3]; +} __attribute__ ((packed)); + + +template +uint8_t acpi_checksum(const T *p, size_t off = 0) +{ + uint8_t sum = 0; + const uint8_t *c = reinterpret_cast(p); + for (int i = off; i < sizeof(T); ++i) sum += c[i]; + return sum; +} + +device_manager::device_manager(const void *root_table) +{ + console *cons = console::get(); + + kassert(root_table != 0, "ACPI root table pointer is null."); + + const Acpi10RSDPDescriptor *acpi1 = + reinterpret_cast(root_table); + + for (int i = 0; i < sizeof(acpi1->signature); ++i) + kassert(acpi1->signature[i] == expected_signature[i], + "ACPI RSDP table signature mismatch"); + + uint8_t sum = acpi_checksum(acpi1, 0); + kassert(sum == 0, "ACPI 1.0 RSDP checksum mismatch."); + + kassert(acpi1->revision > 1, "ACPI 1.0 not supported."); + + const Acpi20RSDPDescriptor *acpi2 = + reinterpret_cast(acpi1); + + sum = acpi_checksum(acpi2, sizeof(Acpi10RSDPDescriptor)); + kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch."); + + cons->puts("ACPI 2.0 tables loading...\n"); +} diff --git a/src/modules/main/device_manager.h b/src/modules/main/device_manager.h new file mode 100644 index 0000000..2a42f0f --- /dev/null +++ b/src/modules/main/device_manager.h @@ -0,0 +1,10 @@ +#pragma once + +class device_manager +{ +public: + device_manager(const void *root_table); + + device_manager() = delete; + device_manager(const device_manager &) = delete; +}; diff --git a/src/modules/main/interrupt_isrs.inc b/src/modules/main/interrupt_isrs.inc new file mode 100644 index 0000000..fd79c8f --- /dev/null +++ b/src/modules/main/interrupt_isrs.inc @@ -0,0 +1,32 @@ +ISR( 0, isr0); +ISR( 1, isr1); +ISR( 2, isr2); +ISR( 3, isr3); +ISR( 4, isr4); +ISR( 5, isr5); +ISR( 6, isr6); +ISR( 7, isr7); +ISR( 8, isr8); +ISR( 9, isr9); +ISR(10, isr10); +ISR(11, isr11); +ISR(12, isr12); +ISR(13, isr13); +ISR(14, isr14); +ISR(15, isr15); +ISR(16, isr16); +ISR(17, isr17); +ISR(18, isr18); +ISR(19, isr19); +ISR(20, isr20); +ISR(21, isr21); +ISR(22, isr22); +ISR(23, isr23); +ISR(24, isr24); +ISR(25, isr25); +ISR(26, isr26); +ISR(27, isr27); +ISR(28, isr28); +ISR(29, isr29); +ISR(30, isr30); +ISR(31, isr31); diff --git a/src/modules/main/interrupts.cpp b/src/modules/main/interrupts.cpp new file mode 100644 index 0000000..fee8b92 --- /dev/null +++ b/src/modules/main/interrupts.cpp @@ -0,0 +1,297 @@ +#include +#include + +#include "console.h" +#include "interrupts.h" + +enum class gdt_flags : uint8_t +{ + ac = 0x01, + rw = 0x02, + dc = 0x04, + ex = 0x08, + r1 = 0x20, + r2 = 0x40, + r3 = 0x60, + pr = 0x80, + + res_1 = 0x10 +}; + +inline gdt_flags +operator | (gdt_flags lhs, gdt_flags rhs) +{ + return static_cast( + static_cast(lhs) | static_cast(rhs)); +} + +struct gdt_descriptor +{ + uint16_t limit_low; + uint16_t base_low; + uint8_t base_mid; + uint8_t flags; + uint8_t granularity; + uint8_t base_high; +} __attribute__ ((packed)); + +struct idt_descriptor +{ + uint16_t base_low; + uint16_t selector; + uint8_t ist; + uint8_t flags; + uint16_t base_mid; + uint32_t base_high; + uint32_t reserved; // must be zero +} __attribute__ ((packed)); + +struct table_ptr +{ + uint16_t limit; + uint64_t base; +} __attribute__ ((packed)); + +gdt_descriptor g_gdt_table[10]; +idt_descriptor g_idt_table[256]; +table_ptr g_gdtr; +table_ptr g_idtr; + + +struct registers; + +extern "C" { + void idt_write(); + void idt_load(); + + void gdt_write(); + void gdt_load(); + + void isr_handler(registers); + +#define ISR(i, name) extern void name () +#include "interrupt_isrs.inc" +#undef ISR +} + +void idt_dump(const table_ptr &table); +void gdt_dump(const table_ptr &table); + +void +set_gdt_entry(uint8_t i, uint32_t base, uint32_t limit, bool is64, gdt_flags flags) +{ + g_gdt_table[i].limit_low = limit & 0xffff; + + g_gdt_table[i].base_low = base & 0xffff; + g_gdt_table[i].base_mid = (base >> 16) & 0xff; + g_gdt_table[i].base_high = (base >> 24) & 0xff; + + g_gdt_table[i].granularity = + ((limit >> 16) & 0xf) | (is64 ? 0xa0 : 0xc0); + + g_gdt_table[i].flags = static_cast(flags | gdt_flags::res_1 | gdt_flags::pr); +} + +void +set_idt_entry(uint8_t i, uint64_t addr, uint16_t selector, uint8_t flags) +{ + g_idt_table[i].base_low = addr & 0xffff; + g_idt_table[i].base_mid = (addr >> 16) & 0xffff; + g_idt_table[i].base_high = (addr >> 32) & 0xffffffff; + g_idt_table[i].selector = selector; + g_idt_table[i].flags = flags; + g_idt_table[i].ist = 0; + g_idt_table[i].reserved = 0; +} + +void +interrupts_init() +{ + uint8_t *p; + + gdt_load(); + gdt_dump(g_gdtr); + + p = reinterpret_cast(&g_gdt_table); + for (int i = 0; i < sizeof(g_gdt_table); ++i) p[i] = 0; + + g_gdtr.limit = sizeof(g_gdt_table) - 1; + g_gdtr.base = reinterpret_cast(&g_gdt_table); + + set_gdt_entry(1, 0, 0xfffff, false, gdt_flags::rw); + set_gdt_entry(2, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex | gdt_flags::dc); + set_gdt_entry(3, 0, 0xfffff, false, gdt_flags::rw); + set_gdt_entry(4, 0, 0xfffff, false, gdt_flags::rw | gdt_flags::ex); + + set_gdt_entry(6, 0, 0xfffff, false, gdt_flags::rw); + set_gdt_entry(7, 0, 0xfffff, true, gdt_flags::rw | gdt_flags::ex); + + gdt_write(); + gdt_load(); + gdt_dump(g_gdtr); + + p = reinterpret_cast(&g_idt_table); + for (int i = 0; i < sizeof(g_idt_table); ++i) p[i] = 0; + + g_idtr.limit = sizeof(g_idt_table) - 1; + g_idtr.base = reinterpret_cast(&g_idt_table); + +#define ISR(i, name) set_idt_entry(i, reinterpret_cast(& name), 0x38, 0x8e); +#include "interrupt_isrs.inc" +#undef ISR + + idt_write(); +} + +struct registers +{ + uint64_t ds; + uint64_t rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax; + uint64_t interrupt, errorcode; + uint64_t rip, cs, eflags, user_esp, ss; +}; + +void +isr_handler(registers regs) +{ + console::get()->puts("received interrupt: "); + console::get()->put_dec(regs.interrupt); + console::get()->puts("\n"); + while(1); +} + + +void +gdt_dump(const table_ptr &table) +{ + console *cons = console::get(); + + cons->puts("Loaded GDT at: "); + cons->put_hex(table.base); + cons->puts(" size: "); + cons->put_dec(table.limit + 1); + cons->puts(" bytes\n"); + + int count = (table.limit + 1) / sizeof(gdt_descriptor); + const gdt_descriptor *gdt = + reinterpret_cast(table.base); + for (int i = 0; i < count; ++i) { + uint32_t base = + (gdt[i].base_high << 24) | + (gdt[i].base_mid << 16) | + gdt[i].base_low; + + uint32_t limit = + static_cast(gdt[i].granularity & 0x0f) << 16 | + gdt[i].limit_low; + + cons->puts(" Entry "); + cons->put_dec(i); + + cons->puts(": Base "); + cons->put_hex(base); + + cons->puts(" Limit "); + cons->put_hex(limit); + + cons->puts(" Privs "); + cons->put_dec((gdt[i].flags >> 5) & 0x03); + + cons->puts(" Flags "); + + if (gdt[i].flags & 0x80) { + cons->puts("P "); + + if (gdt[i].flags & 0x08) + cons->puts("EX "); + else + cons->puts(" "); + + if (gdt[i].flags & 0x04) + cons->puts("DC "); + else + cons->puts(" "); + + if (gdt[i].flags & 0x02) + cons->puts("RW "); + else + cons->puts(" "); + + if (gdt[i].granularity & 0x80) + cons->puts("KB "); + else + cons->puts(" B "); + + if ((gdt[i].granularity & 0x60) == 0x20) + cons->puts("64"); + else if ((gdt[i].granularity & 0x60) == 0x40) + cons->puts("32"); + else + cons->puts("16"); + } + + cons->puts("\n"); + } +} + +void +idt_dump(const table_ptr &table) +{ + console *cons = console::get(); + + cons->puts("Loaded IDT at: "); + cons->put_hex(table.base); + cons->puts(" size: "); + cons->put_dec(table.limit + 1); + cons->puts(" bytes\n"); + + int count = (table.limit + 1) / sizeof(idt_descriptor); + const idt_descriptor *idt = + reinterpret_cast(table.base); + + if (count > 32) count = 32; + for (int i = 0; i < count; ++i) { + uint64_t base = + (static_cast(idt[i].base_high) << 32) | + (static_cast(idt[i].base_mid) << 16) | + idt[i].base_low; + + cons->puts(" Entry "); + cons->put_dec(i); + + cons->puts(": Base "); + cons->put_hex(base); + + cons->puts(" Sel("); + cons->put_dec(idt[i].selector & 0x3); + cons->puts(","); + cons->put_dec((idt[i].selector & 0x4) >> 2); + cons->puts(","); + cons->put_dec(idt[i].selector >> 3); + cons->puts(") "); + + cons->puts("IST "); + cons->put_dec(idt[i].ist); + + switch (idt[i].flags & 0xf) { + case 0x5: cons->puts(" 32tsk "); break; + case 0x6: cons->puts(" 16int "); break; + case 0x7: cons->puts(" 16trp "); break; + case 0xe: cons->puts(" 32int "); break; + case 0xf: cons->puts(" 32trp "); break; + default: + cons->puts(" ?"); + cons->put_hex(idt[i].flags & 0xf); + cons->puts(" "); + break; + } + + cons->puts("DPL "); + cons->put_dec((idt[i].flags >> 5) & 0x3); + + if (idt[i].flags & 0x80) + cons->puts(" P"); + + cons->puts("\n"); + } +} diff --git a/src/modules/main/interrupts.h b/src/modules/main/interrupts.h new file mode 100644 index 0000000..c001ae0 --- /dev/null +++ b/src/modules/main/interrupts.h @@ -0,0 +1,8 @@ +#pragma once + +extern "C" { + void interrupts_enable(); + void interrupts_disable(); +} + +void interrupts_init(); diff --git a/src/modules/main/interrupts.s b/src/modules/main/interrupts.s new file mode 100644 index 0000000..02b14fc --- /dev/null +++ b/src/modules/main/interrupts.s @@ -0,0 +1,112 @@ +extern g_idtr +extern g_gdtr + +global idt_write +idt_write: + lidt [g_idtr] + ret + +global idt_load +idt_load: + sidt [g_idtr] + ret + +global gdt_write +gdt_write: + lgdt [g_gdtr] + ret + +global gdt_load +gdt_load: + sgdt [g_gdtr] + ret + +%macro ISR_NOERRCODE 1 + global isr%1 + isr%1: + cli + push byte 0 + push byte %1 + jmp isr_handler_prelude +%endmacro + +%macro ISR_ERRCODE 1 + global isr%1 + isr%1: + cli + push byte %1 + jmp isr_handler_prelude +%endmacro + +ISR_NOERRCODE 0 +ISR_NOERRCODE 1 +ISR_NOERRCODE 2 +ISR_NOERRCODE 3 +ISR_NOERRCODE 4 +ISR_NOERRCODE 5 +ISR_NOERRCODE 6 +ISR_NOERRCODE 7 +ISR_ERRCODE 8 +ISR_NOERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NOERRCODE 15 +ISR_NOERRCODE 16 +ISR_NOERRCODE 17 +ISR_NOERRCODE 18 +ISR_NOERRCODE 19 +ISR_NOERRCODE 20 +ISR_NOERRCODE 21 +ISR_NOERRCODE 22 +ISR_NOERRCODE 23 +ISR_NOERRCODE 24 +ISR_NOERRCODE 25 +ISR_NOERRCODE 26 +ISR_NOERRCODE 27 +ISR_NOERRCODE 28 +ISR_NOERRCODE 29 +ISR_NOERRCODE 30 +ISR_NOERRCODE 31 + +extern isr_handler +global isr_handler_prelude +isr_handler_prelude: + push rax + push rcx + push rdx + push rbx + push rbp + push rsi + push rdi + + mov ax, ds ; Save the data segment register + push rax + + mov ax, 0x10 ; load the kernel data segment + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + call isr_handler + + pop rax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + pop rdi + pop rsi + pop rbp + pop rbx + pop rdx + pop rcx + pop rax + + add rsp, 8 ; because the ISRs added err/num + sti + iretq diff --git a/src/modules/main/main.cpp b/src/modules/main/main.cpp index e68e2c0..89a46c2 100644 --- a/src/modules/main/main.cpp +++ b/src/modules/main/main.cpp @@ -3,6 +3,7 @@ #include "console.h" #include "font.h" +#include "interrupts.h" #include "kernel_data.h" #include "screen.h" @@ -27,6 +28,8 @@ load_console(const popcorn_data *header) header->log_length}; } +extern "C" { void isr31(); } + void kernel_main(popcorn_data *header) { @@ -37,5 +40,14 @@ kernel_main(popcorn_data *header) cons.set_color(0x08, 0x00); cons.puts(GIT_VERSION " booting...\n"); + interrupts_init(); + interrupts_enable(); + + cons.puts("Interrupts initialized.\n"); + + // isr31(); + __asm__ __volatile__("int $31"); + + cons.puts("boogity!"); do_the_set_registers(header); }