From 1943c3e7a139f1446bb026fafffc4f8281aa5f7b Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 26 Mar 2024 13:59:09 +0200 Subject: [PATCH] Kernel: Unify IDT and GDT code between x86_64 and x86_32 The code is pretty much the same, so there are just couple macros differiating initialization. --- kernel/CMakeLists.txt | 7 +- kernel/arch/i686/GDT.cpp | 21 --- kernel/arch/i686/IDT.cpp | 31 ----- kernel/arch/i686/interrupts.S | 134 ++++++++++++++++++++ kernel/arch/x86_64/GDT.cpp | 56 -------- kernel/include/kernel/GDT.h | 80 ++++++++++-- kernel/include/kernel/IDT.h | 26 +++- kernel/include/kernel/InterruptController.h | 1 + kernel/kernel/GDT.cpp | 69 ++++++++++ kernel/{arch/x86_64 => kernel}/IDT.cpp | 39 +++--- kernel/kernel/InterruptController.cpp | 5 + kernel/kernel/Processor.cpp | 13 +- 12 files changed, 335 insertions(+), 147 deletions(-) delete mode 100644 kernel/arch/i686/GDT.cpp delete mode 100644 kernel/arch/i686/IDT.cpp create mode 100644 kernel/arch/i686/interrupts.S delete mode 100644 kernel/arch/x86_64/GDT.cpp create mode 100644 kernel/kernel/GDT.cpp rename kernel/{arch/x86_64 => kernel}/IDT.cpp (93%) diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index f5344d73fd..6dcdefd88a 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -33,6 +33,8 @@ set(KERNEL_SOURCES kernel/FS/TmpFS/FileSystem.cpp kernel/FS/TmpFS/Inode.cpp kernel/FS/VirtualFileSystem.cpp + kernel/GDT.cpp + kernel/IDT.cpp kernel/Input/KeyboardLayout.cpp kernel/Input/KeyEvent.cpp kernel/Input/PS2/Controller.cpp @@ -105,8 +107,6 @@ if("${BANAN_ARCH}" STREQUAL "x86_64") set(KERNEL_SOURCES ${KERNEL_SOURCES} arch/x86_64/boot.S - arch/x86_64/GDT.cpp - arch/x86_64/IDT.cpp arch/x86_64/interrupts.S arch/x86_64/PageTable.cpp arch/x86_64/Signal.S @@ -124,8 +124,7 @@ elseif("${BANAN_ARCH}" STREQUAL "i686") set(KERNEL_SOURCES ${KERNEL_SOURCES} arch/i686/boot.S - arch/i686/GDT.cpp - arch/i686/IDT.cpp + arch/i686/interrupts.S arch/i686/PageTable.cpp arch/i686/Signal.S arch/i686/Syscall.S diff --git a/kernel/arch/i686/GDT.cpp b/kernel/arch/i686/GDT.cpp deleted file mode 100644 index f76d47f025..0000000000 --- a/kernel/arch/i686/GDT.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -namespace Kernel -{ - - GDT* GDT::create() - { - ASSERT_NOT_REACHED(); - } - - void GDT::write_entry(uint8_t, uint32_t, uint32_t, uint8_t, uint8_t) - { - ASSERT_NOT_REACHED(); - } - - void GDT::write_tss() - { - ASSERT_NOT_REACHED(); - } - -} diff --git a/kernel/arch/i686/IDT.cpp b/kernel/arch/i686/IDT.cpp deleted file mode 100644 index b11241fda7..0000000000 --- a/kernel/arch/i686/IDT.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -namespace Kernel -{ - - IDT* IDT::create() - { - ASSERT_NOT_REACHED(); - } - - [[noreturn]] void IDT::force_triple_fault() - { - ASSERT_NOT_REACHED(); - } - - void IDT::register_irq_handler(uint8_t, Interruptable*) - { - ASSERT_NOT_REACHED(); - } - - void IDT::register_interrupt_handler(uint8_t, void (*)()) - { - ASSERT_NOT_REACHED(); - } - - void IDT::register_syscall_handler(uint8_t, void (*)()) - { - ASSERT_NOT_REACHED(); - } - -} diff --git a/kernel/arch/i686/interrupts.S b/kernel/arch/i686/interrupts.S new file mode 100644 index 0000000000..0b74df9cc1 --- /dev/null +++ b/kernel/arch/i686/interrupts.S @@ -0,0 +1,134 @@ +isr_stub: + ud2 + pusha + call cpp_isr_handler + popa + iret + +irq_stub: + ud2 + pusha + call cpp_irq_handler + popa + iret + +// arguments in EAX, EBX, ECX, EDX, ESI, EDI +.global syscall_asm +syscall_asm: + ud2 + pusha + + pushl %esp + addl $36, (%esp) + + pushl %edi + pushl %esi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + + call cpp_syscall_handler + + addl $60, %esp + + popl %edi + popl %esi + popl %ebp + addl $4, %esp + popl %ebx + popl %edx + popl %ecx + addl $4, %esp + + iret + +.macro isr n + .global isr\n + isr\n: + pushl $0 + pushl $\n + jmp isr_stub +.endm + +.macro isr_err n + .global isr\n + isr\n: + pushl $\n + jmp isr_stub +.endm + +.macro irq n + .global irq\n + irq\n: + pushl $0 + pushl $\n + jmp irq_stub +.endm + +isr 0 +isr 1 +isr 2 +isr 3 +isr 4 +isr 5 +isr 6 +isr 7 +isr_err 8 +isr 9 +isr_err 10 +isr_err 11 +isr_err 12 +isr_err 13 +isr_err 14 +isr 15 +isr 16 +isr_err 17 +isr 18 +isr 19 +isr 20 +isr 21 +isr 22 +isr 23 +isr 24 +isr 25 +isr 26 +isr 27 +isr 28 +isr 29 +isr 30 +isr 31 + +irq 0 +irq 1 +irq 2 +irq 3 +irq 4 +irq 5 +irq 6 +irq 7 +irq 8 +irq 9 +irq 10 +irq 11 +irq 12 +irq 13 +irq 14 +irq 15 +irq 16 +irq 17 +irq 18 +irq 19 +irq 20 +irq 21 +irq 22 +irq 23 +irq 24 +irq 25 +irq 26 +irq 27 +irq 28 +irq 29 +irq 30 +irq 31 +irq 32 diff --git a/kernel/arch/x86_64/GDT.cpp b/kernel/arch/x86_64/GDT.cpp deleted file mode 100644 index 18f0b61ac2..0000000000 --- a/kernel/arch/x86_64/GDT.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include - -#include - -namespace Kernel -{ - - GDT* GDT::create() - { - auto* gdt = new GDT(); - ASSERT(gdt); - - gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null - gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code - gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data - gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code - gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data - gdt->write_tss(); - - return gdt; - } - - void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) - { - ASSERT(offset % sizeof(SegmentDescriptor) == 0); - uint8_t idx = offset / sizeof(SegmentDescriptor); - - auto& desc = m_gdt[idx]; - desc.base1 = (base >> 0) & 0xFFFF; - desc.base2 = (base >> 16) & 0xFF; - desc.base3 = (base >> 24) & 0xFF; - - desc.limit1 = (limit >> 0) & 0xFFFF; - desc.limit2 = (limit >> 16) & 0x0F; - - desc.access = access & 0xFF; - - desc.flags = flags & 0x0F; - } - - void GDT::write_tss() - { - memset(&m_tss, 0x00, sizeof(TaskStateSegment)); - m_tss.iopb = sizeof(TaskStateSegment); - - uint64_t base = reinterpret_cast(&m_tss); - - write_entry(0x28, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0); - - auto& desc = m_gdt[0x30 / sizeof(SegmentDescriptor)]; - desc.low = base >> 32; - desc.high = 0; - } - -} diff --git a/kernel/include/kernel/GDT.h b/kernel/include/kernel/GDT.h index a4bb623e00..56efc2cced 100644 --- a/kernel/include/kernel/GDT.h +++ b/kernel/include/kernel/GDT.h @@ -2,12 +2,14 @@ #include #include +#include #include namespace Kernel { +#if ARCH(x86_64) struct TaskStateSegment { uint32_t reserved1; @@ -26,6 +28,54 @@ namespace Kernel uint16_t reserved4; uint16_t iopb; } __attribute__((packed)); + static_assert(sizeof(TaskStateSegment) == 104); +#elif ARCH(i686) + struct TaskStateSegment + { + uint16_t link; + uint16_t __reserved0; + uint32_t esp0; + uint16_t ss0; + uint16_t __reserved1; + uint32_t esp1; + uint16_t ss1; + uint16_t __reserved2; + uint32_t esp2; + uint16_t ss2; + uint16_t __reserved3; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint16_t es; + uint16_t __reserved4; + uint16_t cs; + uint16_t __reserved5; + uint16_t ss; + uint16_t __reserved6; + uint16_t ds; + uint16_t __reserved7; + uint16_t fs; + uint16_t __reserved8; + uint16_t gs; + uint16_t __reserved9; + uint16_t ldtr; + uint16_t __reserved10; + uint16_t __reserved11; + uint16_t iopb; + uint32_t ssp; + }; + static_assert(sizeof(TaskStateSegment) == 108); +#else + #error +#endif union SegmentDescriptor { @@ -38,20 +88,20 @@ namespace Kernel uint8_t limit2 : 4; uint8_t flags : 4; uint8_t base3; - } __attribute__((packed)); + }; struct { uint32_t low; uint32_t high; - } __attribute__((packed)); - - } __attribute__((packed)); + }; + }; + static_assert(sizeof(SegmentDescriptor) == 8); struct GDTR { uint16_t size; - uint64_t address; + uintptr_t address; } __attribute__((packed)); class GDT @@ -60,7 +110,7 @@ namespace Kernel BAN_NON_MOVABLE(GDT); public: - static GDT* create(); + static GDT* create(void* processor); void load() { flush_gdt(); flush_tss(); } static constexpr inline bool is_user_segment(uint8_t segment) @@ -68,9 +118,13 @@ namespace Kernel return (segment & 3) == 3; } - void set_tss_stack(uintptr_t rsp) + void set_tss_stack(uintptr_t sp) { - m_tss.rsp0 = rsp; +#if ARCH(x86_64) + m_tss.rsp0 = sp; +#elif ARCH(i686) + m_tss.esp0 = sp; +#endif } private: @@ -86,15 +140,21 @@ namespace Kernel void flush_tss() { - asm volatile("ltr %0" :: "rm"((uint16_t)0x28) : "memory"); + asm volatile("ltr %0" :: "rm"(m_tss_offset) : "memory"); } private: +#if ARCH(x86_64) BAN::Array m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high + static constexpr uint16_t m_tss_offset = 0x28; +#elif ARCH(i686) + BAN::Array m_gdt; // null, kernel code, kernel data, user code, user data, processor data, tss + static constexpr uint16_t m_tss_offset = 0x30; +#endif TaskStateSegment m_tss; const GDTR m_gdtr { .size = m_gdt.size() * sizeof(SegmentDescriptor) - 1, - .address = reinterpret_cast(m_gdt.data()) + .address = reinterpret_cast(m_gdt.data()) }; }; diff --git a/kernel/include/kernel/IDT.h b/kernel/include/kernel/IDT.h index b99a66f298..1c8b9db484 100644 --- a/kernel/include/kernel/IDT.h +++ b/kernel/include/kernel/IDT.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -12,21 +13,36 @@ constexpr uint8_t IRQ_IPI = 32; namespace Kernel { +#if ARCH(x86_64) struct GateDescriptor { - uint16_t offset1; + uint16_t offset0; uint16_t selector; uint8_t IST; uint8_t flags; - uint16_t offset2; - uint32_t offset3; + uint16_t offset1; + uint32_t offset2; uint32_t reserved; - } __attribute__((packed)); + }; + static_assert(sizeof(GateDescriptor) == 16); +#elif ARCH(i686) + struct GateDescriptor + { + uint16_t offset0; + uint16_t selector; + uint8_t reserved; + uint8_t flags; + uint16_t offset1; + }; + static_assert(sizeof(GateDescriptor) == 8); +#else + #error +#endif struct IDTR { uint16_t size; - uint64_t offset; + uintptr_t offset; } __attribute__((packed)); class IDT diff --git a/kernel/include/kernel/InterruptController.h b/kernel/include/kernel/InterruptController.h index 115d011220..b430e9837f 100644 --- a/kernel/include/kernel/InterruptController.h +++ b/kernel/include/kernel/InterruptController.h @@ -18,6 +18,7 @@ namespace Kernel virtual bool is_in_service(uint8_t) = 0; static void initialize(bool force_pic); + static bool is_initialized(); static InterruptController& get(); virtual void initialize_multiprocessor() = 0; diff --git a/kernel/kernel/GDT.cpp b/kernel/kernel/GDT.cpp new file mode 100644 index 0000000000..302a82ed8b --- /dev/null +++ b/kernel/kernel/GDT.cpp @@ -0,0 +1,69 @@ +#include +#include + +#include + +namespace Kernel +{ + + GDT* GDT::create([[maybe_unused]] void* processor) + { + auto* gdt = new GDT(); + ASSERT(gdt); + +#if ARCH(x86_64) + constexpr uint8_t code_flags = 0xA; + constexpr uint8_t data_flags = 0xC; +#elif ARCH(i686) + constexpr uint8_t code_flags = 0xC; + constexpr uint8_t data_flags = 0xC; +#endif + + gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null + gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, code_flags); // kernel code + gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, data_flags); // kernel data + gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, code_flags); // user code + gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, data_flags); // user data +#if ARCH(i686) + gdt->write_entry(0x28, reinterpret_cast(processor), sizeof(Processor), 0x92, 0x4); // processor data +#endif + gdt->write_tss(); + + return gdt; + } + + void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) + { + ASSERT(offset % sizeof(SegmentDescriptor) == 0); + uint8_t idx = offset / sizeof(SegmentDescriptor); + + auto& desc = m_gdt[idx]; + desc.base1 = (base >> 0) & 0xFFFF; + desc.base2 = (base >> 16) & 0xFF; + desc.base3 = (base >> 24) & 0xFF; + + desc.limit1 = (limit >> 0) & 0xFFFF; + desc.limit2 = (limit >> 16) & 0x0F; + + desc.access = access & 0xFF; + + desc.flags = flags & 0x0F; + } + + void GDT::write_tss() + { + memset(&m_tss, 0x00, sizeof(TaskStateSegment)); + m_tss.iopb = sizeof(TaskStateSegment); + + uintptr_t base = reinterpret_cast(&m_tss); + + write_entry(m_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0); + +#if ARCH(x86_64) + auto& desc = m_gdt[(m_tss_offset + 8) / sizeof(SegmentDescriptor)]; + desc.low = base >> 32; + desc.high = 0; +#endif + } + +} diff --git a/kernel/arch/x86_64/IDT.cpp b/kernel/kernel/IDT.cpp similarity index 93% rename from kernel/arch/x86_64/IDT.cpp rename to kernel/kernel/IDT.cpp index 0cf1531654..844a93e78a 100644 --- a/kernel/arch/x86_64/IDT.cpp +++ b/kernel/kernel/IDT.cpp @@ -141,21 +141,16 @@ namespace Kernel "Unkown Exception 0x1F", }; - extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs) + extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack& interrupt_stack, const Registers* regs) { if (g_paniced) { dprintln("Processor {} halted", Processor::current_id()); - InterruptController::get().broadcast_ipi(); + if (InterruptController::is_initialized()) + InterruptController::get().broadcast_ipi(); asm volatile("cli; 1: hlt; jmp 1b"); } -#if __enable_sse - bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11; - if (from_userspace) - Thread::current().save_sse(); -#endif - pid_t tid = Scheduler::current_tid(); pid_t pid = tid ? Process::current().pid() : 0; @@ -209,11 +204,19 @@ namespace Kernel #if __enable_sse else if (isr == ISR::DeviceNotAvailable) { +#if ARCH(x86_64) asm volatile( "movq %cr0, %rax;" "andq $~(1 << 3), %rax;" "movq %rax, %cr0;" ); +#elif ARCH(i686) + asm volatile( + "movl %cr0, %eax;" + "andl $~(1 << 3), %eax;" + "movl %eax, %cr0;" + ); +#endif if (auto* current = &Thread::current(); current != Thread::sse_thread()) { if (auto* sse = Thread::sse_thread()) @@ -302,7 +305,8 @@ done: if (g_paniced) { dprintln("Processor {} halted", Processor::current_id()); - InterruptController::get().broadcast_ipi(); + if (InterruptController::is_initialized()) + InterruptController::get().broadcast_ipi(); asm volatile("cli; 1: hlt; jmp 1b"); } @@ -332,14 +336,17 @@ done: void IDT::register_interrupt_handler(uint8_t index, void (*handler)()) { - auto& descriptor = m_idt[index]; - descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0); - descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16); - descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32); + auto& desc = m_idt[index]; + memset(&desc, 0, sizeof(GateDescriptor)); - descriptor.selector = 0x08; - descriptor.IST = 0; - descriptor.flags = 0x8E; + desc.offset0 = (uint16_t)((uintptr_t)handler >> 0); + desc.offset1 = (uint16_t)((uintptr_t)handler >> 16); +#if ARCH(x86_64) + desc.offset2 = (uint32_t)((uintptr_t)handler >> 32); +#endif + + desc.selector = 0x08; + desc.flags = 0x8E; } void IDT::register_syscall_handler(uint8_t index, void (*handler)()) diff --git a/kernel/kernel/InterruptController.cpp b/kernel/kernel/InterruptController.cpp index 6cd043925f..5aa8e19d17 100644 --- a/kernel/kernel/InterruptController.cpp +++ b/kernel/kernel/InterruptController.cpp @@ -40,6 +40,11 @@ namespace Kernel s_instance->m_using_apic = false; } + bool InterruptController::is_initialized() + { + return s_instance; + } + void InterruptController::enter_acpi_mode() { #if ARCH(x86_64) diff --git a/kernel/kernel/Processor.cpp b/kernel/kernel/Processor.cpp index a9b6acd819..2fbab9b826 100644 --- a/kernel/kernel/Processor.cpp +++ b/kernel/kernel/Processor.cpp @@ -38,7 +38,7 @@ namespace Kernel processor.m_stack = kmalloc(s_stack_size, 4096, true); ASSERT(processor.m_stack); - processor.m_gdt = GDT::create(); + processor.m_gdt = GDT::create(&processor); ASSERT(processor.m_gdt); processor.m_idt = IDT::create(); @@ -52,14 +52,19 @@ namespace Kernel auto id = read_processor_id(); auto& processor = s_processors[id]; + ASSERT(processor.m_gdt); + processor.m_gdt->load(); + + // initialize GS +#if ARCH(x86_64) // set gs base to pointer to this processor uint64_t ptr = reinterpret_cast(&processor); uint32_t ptr_hi = ptr >> 32; uint32_t ptr_lo = ptr & 0xFFFFFFFF; asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_GS_BASE)); - - ASSERT(processor.m_gdt); - processor.gdt().load(); +#elif ARCH(i686) + asm volatile("movw $0x28, %%ax; movw %%ax, %%gs" ::: "ax"); +#endif ASSERT(processor.m_idt); processor.idt().load();