From 09cf6b4ca8799990b9c01db04c5f4ffbef798773 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Sun, 28 Feb 2021 14:53:13 +0200 Subject: Fix interrupts causing exception 0xd --- .gitignore | 2 ++ libk/stdlib/abort.cc | 11 +++++-- src/cpu/exceptions.s | 51 ++++++++++++++++++++++++++++++ src/cpu/interrupts.s | 50 +++++++++++++++++++++++++++++ src/gdt.cc | 9 ++++++ src/gdt.h | 2 ++ src/idt.cc | 89 ++++++++++++++++++++++++++++++---------------------- src/idt.h | 46 +++++++-------------------- src/irq/kirq.cc | 21 ------------- src/kernel.cc | 9 +----- src/makefile | 15 +++++++-- 11 files changed, 198 insertions(+), 107 deletions(-) create mode 100644 src/cpu/exceptions.s create mode 100644 src/cpu/interrupts.s delete mode 100644 src/irq/kirq.cc diff --git a/.gitignore b/.gitignore index 5ef19a0..5873c6f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ build/ isodir/ drivers/hardware.h +src/cpu/irq.h + .config.old *.tar* diff --git a/libk/stdlib/abort.cc b/libk/stdlib/abort.cc index 56ca7ee..41bf991 100644 --- a/libk/stdlib/abort.cc +++ b/libk/stdlib/abort.cc @@ -8,8 +8,13 @@ void abort() { */ asm volatile("cli"); - while (true) { - asm volatile("hlt"); - } + while (true) asm volatile("hlt"); __builtin_unreachable(); } + +extern "C" void print_exception(uint8_t irq) { + printk("exception ", uhex{irq}, '\n'); + asm volatile("cli"); + while (true) asm volatile("hlt"); + __builtin_unreachable(); +}; diff --git a/src/cpu/exceptions.s b/src/cpu/exceptions.s new file mode 100644 index 0000000..9736be1 --- /dev/null +++ b/src/cpu/exceptions.s @@ -0,0 +1,51 @@ +.section .text +.extern print_exception + +.macro exception num +.global exception\num +exception\num: + movb $\num, (exc) + jmp exception_common +.endm + +exception 0x00 +exception 0x01 +exception 0x02 +exception 0x03 +exception 0x04 +exception 0x05 +exception 0x06 +exception 0x07 +exception 0x08 +exception 0x09 +exception 0x0a +exception 0x0b +exception 0x0c +exception 0x0d +exception 0x0e +exception 0x0f +exception 0x10 +exception 0x11 +exception 0x12 +exception 0x13 + +exception_common: + pusha + pushl %ds + pushl %es + pushl %fs + pushl %gs + + push (exc) + call print_exception + + popl %gs + popl %fs + popl %es + popl %ds + popa + iret + +.data + exc: .byte 0 + diff --git a/src/cpu/interrupts.s b/src/cpu/interrupts.s new file mode 100644 index 0000000..17c39e9 --- /dev/null +++ b/src/cpu/interrupts.s @@ -0,0 +1,50 @@ +.section .text +.extern handle_interrupt + +.macro interrupt num +.global interrupt\num +interrupt\num: + movb $\num, (irq) + jmp interrupt_common +.endm + +interrupt 0x00 # system timer +interrupt 0x01 # keyboard controller +interrupt 0x02 # slave pic +interrupt 0x03 # serial port 2 and 4 +interrupt 0x04 # serial port 1 and 3 +interrupt 0x05 # parallel port 2 and 3, sound card +interrupt 0x06 # floppy controller +interrupt 0x07 # parallel port 1 + +interrupt 0x08 # real-time clock +interrupt 0x09 # acpi +interrupt 0x0a # +interrupt 0x0b # +interrupt 0x0c # mouse on ps/2 +interrupt 0x0d # fpu +interrupt 0x0e # primary ATA +interrupt 0x0f # secondary ATA + +interrupt_common: + pusha + pushl %ds + pushl %es + pushl %fs + pushl %gs + + pushl %esp + push (irq) + call handle_interrupt + mov %eax, %esp + + popl %gs + popl %fs + popl %es + popl %ds + popa + iret + +.data + irq: .byte 0 + diff --git a/src/gdt.cc b/src/gdt.cc index 289462b..9c86888 100644 --- a/src/gdt.cc +++ b/src/gdt.cc @@ -1,12 +1,21 @@ #include "gdt.h" +#include using seg = GDT::SegmentDescriptor; GDT::GDT() : segments{seg::make<0>(0, {.present = false}), // null segment + seg::make<0>(0, {.present = false}), // unused segment ??? seg::make<0xffffffff>(0, {.r_w = true, .exe = true, .segment = true}), // code segment seg::make<0xffffffff>(0, {.r_w = true, .segment = true})} // data segment { Pointer gdtr{.limit = sizeof(segments) - 1, .base = reinterpret_cast(segments)}; asm volatile("lgdt %0" : : "p"(gdtr)); + + printk("GDT installed at ", uhex{gdtr.base}, '\n'); +} + +uint16_t GDT::codeDescriptor() const { + return static_cast(reinterpret_cast(&segments[2]) - + reinterpret_cast(&segments)); } diff --git a/src/gdt.h b/src/gdt.h index a86a14f..bb7181b 100644 --- a/src/gdt.h +++ b/src/gdt.h @@ -30,6 +30,8 @@ public: GDT(); ~GDT() = default; + uint16_t codeDescriptor() const; + struct Pointer { uint16_t limit; uint32_t base; diff --git a/src/idt.cc b/src/idt.cc index e4c21b7..fefe53e 100644 --- a/src/idt.cc +++ b/src/idt.cc @@ -1,11 +1,10 @@ #include "idt.h" #include +#include "cpu/irq.h" #include "ports.h" static_assert(sizeof(IDT::Pointer) == 6); -// size of IDT::Entry in protected mode is 64 bits -// and in long mode is 128 bits -static_assert(sizeof(IDT::Entry) == 8); +static_assert(sizeof(IDT::Entry) == 8); // size of IDT::Entry in protected mode is 64 bits /* reinitialize the PIC controllers, giving them specified vector offsets rather than 8h and 70h, as configured by default */ @@ -22,60 +21,74 @@ static_assert(sizeof(IDT::Entry) == 8); #define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ #define ICW4_SFNM 0x10 /* Special fully nested (not) */ -template -__attribute__((interrupt)) void t_irq(interrupt_frame*) { - static_assert(irq <= 15); - - com1_port_t com1; - com1.write("0123456789abcdef"[irq]); - com1.write('\n'); - com1.write('\r'); - +extern "C" uint32_t handle_interrupt(uint8_t irq, uint32_t esp) { + printk("interrupt ", uhex{irq}, '\n'); pic1_t pic1; pic1.write(0x20); - if constexpr (irq > 7) { + if (irq > 7) { pic2_t pic2; pic2.write(0x20); } + return esp; }; -IDT::IDT() { +IDT::IDT(const uint16_t selector) { + table[0x00] = Entry(&exception0x00, selector, Intr); + table[0x01] = Entry(&exception0x01, selector, Intr); + table[0x02] = Entry(&exception0x02, selector, Intr); + table[0x03] = Entry(&exception0x03, selector, Intr); + table[0x04] = Entry(&exception0x04, selector, Intr); + table[0x05] = Entry(&exception0x05, selector, Intr); + table[0x06] = Entry(&exception0x06, selector, Intr); + table[0x07] = Entry(&exception0x07, selector, Intr); + table[0x08] = Entry(&exception0x08, selector, Intr); + table[0x09] = Entry(&exception0x09, selector, Intr); + table[0x0a] = Entry(&exception0x0a, selector, Intr); + table[0x0b] = Entry(&exception0x0b, selector, Intr); + table[0x0c] = Entry(&exception0x0c, selector, Intr); + table[0x0d] = Entry(&exception0x0d, selector, Intr); + table[0x0e] = Entry(&exception0x0e, selector, Intr); + table[0x0f] = Entry(&exception0x0f, selector, Intr); + table[0x10] = Entry(&exception0x10, selector, Intr); + table[0x11] = Entry(&exception0x11, selector, Intr); + table[0x12] = Entry(&exception0x12, selector, Intr); + table[0x13] = Entry(&exception0x13, selector, Intr); + + table[0x20] = Entry(&interrupt0x00, selector, Intr); + table[0x21] = Entry(&interrupt0x01, selector, Intr); + table[0x22] = Entry(&interrupt0x02, selector, Intr); + table[0x23] = Entry(&interrupt0x03, selector, Intr); + table[0x24] = Entry(&interrupt0x04, selector, Intr); + table[0x25] = Entry(&interrupt0x05, selector, Intr); + table[0x26] = Entry(&interrupt0x06, selector, Intr); + table[0x27] = Entry(&interrupt0x07, selector, Intr); + + table[0x28] = Entry(&interrupt0x08, selector, Intr); + table[0x29] = Entry(&interrupt0x09, selector, Intr); + table[0x2a] = Entry(&interrupt0x0a, selector, Intr); + table[0x2b] = Entry(&interrupt0x0b, selector, Intr); + table[0x2c] = Entry(&interrupt0x0c, selector, Intr); + table[0x2d] = Entry(&interrupt0x0d, selector, Intr); + table[0x2e] = Entry(&interrupt0x0e, selector, Intr); + table[0x2f] = Entry(&interrupt0x0f, selector, Intr); + pic1_t pic1; pic2_t pic2; - // const auto mask1 = pic1.read(0x1); - // const auto mask2 = pic2.read(0x1); - pic1.write(ICW1_INIT | ICW1_ICW4); pic2.write(ICW1_INIT | ICW1_ICW4); pic1.write(0x20, 0x1); // offset 0x20 pic2.write(0x28, 0x1); // offset 0x28 - pic1.write(4, 0x1); // tell master pic there is a slave pic - pic2.write(2, 0x1); // tell slave pic its cascade identity + pic1.write(0x04, 0x1); // tell master pic there is a slave pic + pic2.write(0x02, 0x1); // tell slave pic its cascade identity + pic1.write(ICW4_8086, 0x1); pic2.write(ICW4_8086, 0x1); - // pic1.write(mask1); - // pic2.write(mask2); - pic1.write(0xfd, 0x1); // only enable irq1 + // pic masks + pic1.write(0xfc, 0x1); // only enable irq1 pic2.write(0xff, 0x1); - table[0x20] = Entry(reinterpret_cast(t_irq<0x0>), 0x08, InterruptGate); - table[0x21] = Entry(reinterpret_cast(t_irq<0x1>), 0x08, InterruptGate); - table[0x22] = Entry(reinterpret_cast(t_irq<0x2>), 0x08, InterruptGate); - table[0x23] = Entry(reinterpret_cast(t_irq<0x3>), 0x08, InterruptGate); - table[0x24] = Entry(reinterpret_cast(t_irq<0x4>), 0x08, InterruptGate); - table[0x25] = Entry(reinterpret_cast(t_irq<0x5>), 0x08, InterruptGate); - table[0x26] = Entry(reinterpret_cast(t_irq<0x6>), 0x08, InterruptGate); - table[0x27] = Entry(reinterpret_cast(t_irq<0x7>), 0x08, InterruptGate); - table[0x28] = Entry(reinterpret_cast(t_irq<0x8>), 0x08, InterruptGate); - table[0x29] = Entry(reinterpret_cast(t_irq<0x9>), 0x08, InterruptGate); - table[0x2a] = Entry(reinterpret_cast(t_irq<0xa>), 0x08, InterruptGate); - table[0x2b] = Entry(reinterpret_cast(t_irq<0xb>), 0x08, InterruptGate); - table[0x2c] = Entry(reinterpret_cast(t_irq<0xc>), 0x08, InterruptGate); - table[0x2d] = Entry(reinterpret_cast(t_irq<0xd>), 0x08, InterruptGate); - table[0x2e] = Entry(reinterpret_cast(t_irq<0xe>), 0x08, InterruptGate); - Pointer ptr{.limit = sizeof(table), .base = reinterpret_cast(table)}; asm volatile("lidt %0" : : "m"(ptr)); asm volatile("sti"); diff --git a/src/idt.h b/src/idt.h index 628eb23..bc71f05 100644 --- a/src/idt.h +++ b/src/idt.h @@ -11,54 +11,32 @@ public: enum InterruptType : uint8_t { Null = 0, - InterruptGate = 0b110, // hardware interrupts are disabled while the handler runs - TrapGate = 0b111, // hardware interrupts remain active while the handler runs - TaskGate = 0b101, // selector points to TSS rather than a code segment + Task = 0b10000101, // 32-bit task gate selector points to TSS rather than a code segment + Intr = 0b10001110, // 32-bit interrupt hardware interrupts are disabled while the handler runs + Trap = 0b10001111, // 32-bit trap gate hardware interrupts remain active while the handler runs }; class Entry { public: - constexpr Entry(uint32_t offset = 0, uint16_t select = 0, InterruptType t = Null) { - offset_0_15 = offset & 0xffff; - offset_16_31 = (offset & 0xffff0000) >> 16; + constexpr Entry() = default; + Entry(void (*handler)(), uint16_t select, InterruptType t) { + offset_0_15 = reinterpret_cast(handler) & 0xffff; + offset_16_31 = (reinterpret_cast(handler) >> 16) & 0xffff; selector = select; type = t; - if (offset != 0) { - e = true; - } } private: - uint16_t offset_0_15; // 0-15 offset in the segment - uint16_t selector; // 16-31 selector of the code segment + uint16_t offset_0_15 = 0; // 0-15 offset in the segment + uint16_t selector = 0; // 16-31 selector of the code segment [[maybe_unused]] uint8_t null = 0; // 32-39 unused in protected mode - InterruptType type : 3; // 40-42 type - [[maybe_unused]] bool d : 1 = true; // 43 true: 32-bit, false: 16-bit segment - [[maybe_unused]] uint8_t u : 1 = 0; // 44 unused - [[maybe_unused]] uint8_t dpl : 2 = 0; // 45-46 descriptor privilege level - [[maybe_unused]] bool e : 1 = false; // 47 enable - uint16_t offset_16_31; // 48-63 offset high + InterruptType type = Null; // 40-43 type + uint16_t offset_16_31 = 0; // 48-63 offset high } __attribute__((packed)); - IDT(); + IDT(const uint16_t selector); private: Entry table[256]; }; -struct interrupt_frame { - uword_t ip; - uword_t cs; - uword_t flags; - uword_t sp; - uword_t ss; -}; - -/* https://wiki.osdev.org/Interrupt_Service_Routines */ -template -__attribute__((interrupt)) void kirq(interrupt_frame* frame); - -template <> -void kirq<0x0>(interrupt_frame* frame); -template <> -void kirq<0x1>(interrupt_frame* frame); diff --git a/src/irq/kirq.cc b/src/irq/kirq.cc deleted file mode 100644 index acd57d4..0000000 --- a/src/irq/kirq.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include "../idt.h" -#include "ports.h" - -template <> -void kirq<0x0>(interrupt_frame*) { - printk("Interrupt 0x0\n"); - - // send end of interrupt - pic1_t pic1; - pic1.write(0x20); -} - -template <> -void kirq<0x1>(interrupt_frame*) { - printk("Interrupt 0x0\n"); - - // send end of interrupt - pic1_t pic1; - pic1.write(0x20); -} diff --git a/src/kernel.cc b/src/kernel.cc index 4337edb..6bfb021 100644 --- a/src/kernel.cc +++ b/src/kernel.cc @@ -45,15 +45,8 @@ void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t m // dump_multiboot(mb_magic, mb_addr); // dump_gdt(); - // printk("GDT::SegmentDescriptor tests\n"); - auto x = GDT::SegmentDescriptor::make<0xffff>(0xdeadbeef, {}); - // printk("x.base(): ", uhex{x.base()}, '\n'); - - // printk("Setting new GDT\n"); GDT gdt; - // dump_gdt(); - - IDT idt; + IDT idt{gdt.codeDescriptor()}; while (true) asm volatile("hlt"); } diff --git a/src/makefile b/src/makefile index ab08ee2..8b21640 100644 --- a/src/makefile +++ b/src/makefile @@ -1,4 +1,5 @@ -AS_OBJ += src/boot.o +AS_OBJ += src/boot.o \ + src/cpu/exceptions.o src/cpu/interrupts.o CXX_OBJ += src/kernel.o \ src/kernel/dump_gdt.o \ @@ -6,5 +7,13 @@ CXX_OBJ += src/kernel.o \ src/memory.o \ src/gdt.o \ src/gdt/segmentdescriptor.o \ - src/idt.o \ - src/irq/kirq.o + src/idt.o + +src/cpu/irq.h: $(OBJ_DIR)/src/cpu/exceptions.o $(OBJ_DIR)/src/cpu/interrupts.o + @echo " GEN $@" + @echo '#pragma once' > $@ + @echo 'extern "C" {' >> $@ + @for x in $^; do nm $$x -g | sed -nr 's/[0-9a-f]{8} T (.+)/void \1();/p'; done >> $@ + @echo '}' >> $@ + +autogen := $(autogen) src/cpu/irq.h -- cgit v1.2.1