From f2b45ba212bf352ea2724117cef320189d60f8ba Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 16 Nov 2022 19:49:09 +0200 Subject: [PATCH] Add GDT and IDT --- kernel/Makefile | 2 + kernel/include/kernel/GDT.h | 56 ++++++++++++++++++++++ kernel/include/kernel/IDT.h | 27 +++++++++++ kernel/kernel/GDT.cpp | 46 ++++++++++++++++++ kernel/kernel/IDT.cpp | 95 +++++++++++++++++++++++++++++++++++++ kernel/kernel/kernel.cpp | 25 ++++------ 6 files changed, 236 insertions(+), 15 deletions(-) create mode 100644 kernel/include/kernel/GDT.h create mode 100644 kernel/include/kernel/IDT.h create mode 100644 kernel/kernel/GDT.cpp create mode 100644 kernel/kernel/IDT.cpp diff --git a/kernel/Makefile b/kernel/Makefile index e25ef61e..6eb7a55f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -29,6 +29,8 @@ LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS) KERNEL_OBJS=\ $(KERNEL_ARCH_OBJS) \ +kernel/GDT.o \ +kernel/IDT.o \ kernel/kernel.o \ kernel/kmalloc.o \ kernel/SSP.o \ diff --git a/kernel/include/kernel/GDT.h b/kernel/include/kernel/GDT.h new file mode 100644 index 00000000..6f355b8d --- /dev/null +++ b/kernel/include/kernel/GDT.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +union SegmentDesriptor +{ + struct + { + uint16_t limit_lo; + uint16_t base_lo; + uint8_t base_hi1; + + uint8_t type : 4; + uint8_t system : 1; + uint8_t DPL : 2; + uint8_t present : 1; + + uint8_t limit_hi : 4; + uint8_t flags : 4; + + uint8_t base_hi2; + }; + + struct + { + uint32_t low; + uint32_t high; + }; + + SegmentDesriptor() : low(0), high(0) {} + SegmentDesriptor(uint32_t base, uint32_t limit, uint8_t access, uint8_t _flags) + : low(0), high(0) + { + set_base(base); + set_limit(limit); + + high |= ((uint16_t)access) << 8; + flags = _flags; + } + + void set_base(uint32_t base) + { + base_lo = base & 0xFFFF; + base_hi1 = (base >> 16) & 0x00FF; + base_hi2 = (base >> 24) & 0x00FF; + } + + void set_limit(uint32_t limit) + { + limit_lo = limit & 0xFFFF; + limit_hi = (limit >> 16) & 0x00FF; + } + +} __attribute__((packed)); + +void gdt_initialize(); diff --git a/kernel/include/kernel/IDT.h b/kernel/include/kernel/IDT.h new file mode 100644 index 00000000..07ca1969 --- /dev/null +++ b/kernel/include/kernel/IDT.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +union GateDescriptor +{ + struct + { + uint16_t offset_lo; + uint16_t selector; + uint8_t reserved; + uint8_t type : 4; + uint8_t zero : 1; + uint8_t dpl : 2; + uint8_t present : 1; + uint16_t offset_hi; + }; + + struct + { + uint32_t low; + uint32_t high; + }; + +} __attribute__((packed)); + +void idt_initialize(); \ No newline at end of file diff --git a/kernel/kernel/GDT.cpp b/kernel/kernel/GDT.cpp new file mode 100644 index 00000000..040465fc --- /dev/null +++ b/kernel/kernel/GDT.cpp @@ -0,0 +1,46 @@ +#include +#include + +struct GDTR +{ + uint16_t size; + void* address; +} __attribute__((packed)); + +static GDTR s_gdtr; +static SegmentDesriptor* s_gdt; + +void write_gdt_entry_raw(uint8_t index, uint32_t low, uint32_t high) +{ + s_gdt[index].low = low; + s_gdt[index].high = high; +} + +void write_gdt_entry(uint8_t index, SegmentDesriptor descriptor) +{ + write_gdt_entry_raw(index, descriptor.low, descriptor.high); +} + +static void flush_gdt() +{ + asm volatile("lgdt %0"::"m"(s_gdtr)); +} + +void gdt_initialize() +{ + constexpr size_t gdt_size = 256; + + s_gdt = new SegmentDesriptor[gdt_size]; + + s_gdtr.address = s_gdt; + s_gdtr.size = gdt_size * 8 - 1; + + uint8_t index = 0; + write_gdt_entry(index++, { 0, 0x0000, 0x00, 0x0 }); // null + write_gdt_entry(index++, { 0, 0xFFFF, 0x9A, 0xC }); // kernel code + write_gdt_entry(index++, { 0, 0xFFFF, 0x92, 0xC }); // kernel data + write_gdt_entry(index++, { 0, 0xFFFF, 0xFA, 0xC }); // user code + write_gdt_entry(index++, { 0, 0xFFFF, 0xF2, 0xC }); // user data + + flush_gdt(); +} diff --git a/kernel/kernel/IDT.cpp b/kernel/kernel/IDT.cpp new file mode 100644 index 00000000..941d7f4e --- /dev/null +++ b/kernel/kernel/IDT.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +struct IDTR +{ + uint16_t size; + void* offset; +} __attribute((packed)); + +static IDTR s_idtr; +static GateDescriptor* s_idt; + + +#define INTERRUPT_HANDLER(i, msg) \ + static void interrupt ## i () \ + { \ + uint32_t cr0, cr2, cr3, cr4; \ + asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \ + asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \ + asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \ + asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \ + Kernel::panic(msg ", CR0={} CR2={} CR3={} CR4={}\n", cr0, cr2, cr3, cr4); \ + } + +INTERRUPT_HANDLER(0x00, "Divide error") +INTERRUPT_HANDLER(0x01, "Debug exception") +INTERRUPT_HANDLER(0x02, "Unknown error") +INTERRUPT_HANDLER(0x03, "Breakpoint") +INTERRUPT_HANDLER(0x04, "Overflow") +INTERRUPT_HANDLER(0x05, "Bounds check") +INTERRUPT_HANDLER(0x06, "Invalid opcode") +INTERRUPT_HANDLER(0x07, "Coprocessor not available") +INTERRUPT_HANDLER(0x08, "Double fault") +INTERRUPT_HANDLER(0x09, "Coprocessor segment overrun") +INTERRUPT_HANDLER(0x0a, "Invalid TSS") +INTERRUPT_HANDLER(0x0b, "Segment not present") +INTERRUPT_HANDLER(0x0c, "Stack exception") +INTERRUPT_HANDLER(0x0d, "General protection fault") +INTERRUPT_HANDLER(0x0e, "Page fault") +INTERRUPT_HANDLER(0x0f, "Unknown error") +INTERRUPT_HANDLER(0x10, "Coprocessor error") + +#define REGISTER_HANDLER(i) register_interrupt_handeler(i, interrupt ## i) + +static void flush_idt() +{ + asm volatile("lidt %0"::"m"(s_idtr)); +} + +static void unimplemented_trap() +{ + Kernel::panic("Unhandeled IRQ"); +} + +static void register_interrupt_handeler(uint8_t index, void (*f)()) +{ + s_idt[index].low = 0x00080000 | ((uint32_t)(f) & 0x0000ffff); + s_idt[index].high = ((uint32_t)(f) & 0xffff0000) | 0x8e00; + flush_idt(); +} + +void idt_initialize() +{ + constexpr size_t idt_size = 256; + + s_idt = new GateDescriptor[idt_size]; + + s_idtr.offset = s_idt; + s_idtr.size = idt_size * 8; + + REGISTER_HANDLER(0x00); + REGISTER_HANDLER(0x01); + REGISTER_HANDLER(0x02); + REGISTER_HANDLER(0x03); + REGISTER_HANDLER(0x04); + REGISTER_HANDLER(0x05); + REGISTER_HANDLER(0x06); + REGISTER_HANDLER(0x07); + REGISTER_HANDLER(0x08); + REGISTER_HANDLER(0x09); + REGISTER_HANDLER(0x0a); + REGISTER_HANDLER(0x0b); + REGISTER_HANDLER(0x0c); + REGISTER_HANDLER(0x0d); + REGISTER_HANDLER(0x0e); + REGISTER_HANDLER(0x0f); + REGISTER_HANDLER(0x10); + + for (uint16_t i = 0x11; i < idt_size; i++) + register_interrupt_handeler(i, unimplemented_trap); + + flush_idt(); +} diff --git a/kernel/kernel/kernel.cpp b/kernel/kernel/kernel.cpp index bf74ba5d..2a15d2b5 100644 --- a/kernel/kernel/kernel.cpp +++ b/kernel/kernel/kernel.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -17,27 +18,21 @@ extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic) { DISABLE_INTERRUPTS(); + + if (magic != 0x2BADB002) + asm volatile("hlt"); s_multiboot_info = mbi; terminal_initialize(); - if (magic != 0x2BADB002) - Kernel::panic("Invalid magic in multiboot"); + kmalloc_initialize(); - if (!(mbi->flags & (1 << 6))) - Kernel::panic("Bootloader did not provide memory map"); - - for (uint32_t i = 0; i < mbi->mmap_length;) - { - multiboot_memory_map_t* mmmt = (multiboot_memory_map_t*)(mbi->mmap_addr + i); - if (mmmt->type == 1) - kprint("Size: {}, Addr: {}, Length: {}, Type: {}\n", mmmt->size, (void*)mmmt->base_addr, (void*)mmmt->length, mmmt->type); - - i += mmmt->size + sizeof(uint32_t); - } - - printf("Hello from the kernel!\n"); + gdt_initialize(); + idt_initialize(); kprint("Hello from the kernel!\n"); + + asm volatile("int $14"); + } \ No newline at end of file