From a00456084240e11e29fc5eaf9c34227491eaf1dc Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Tue, 16 Feb 2021 22:22:38 +0200 Subject: Add IDT --- .gitignore | 2 ++ drivers/ports.h | 4 ++++ libk/types.h | 9 +++++++++ src/idt.cc | 51 +++++++++++++++++++++++++++++++++++++++++++++++ src/idt.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/irq/kirq.cc | 21 ++++++++++++++++++++ src/kernel.cc | 5 ++++- src/makefile | 4 +++- 8 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 src/idt.cc create mode 100644 src/idt.h create mode 100644 src/irq/kirq.cc diff --git a/.gitignore b/.gitignore index 94e1555..bd048b4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ glitch.elf glitch.iso build/ isodir/ + +*.tar* diff --git a/drivers/ports.h b/drivers/ports.h index 8671f19..98cac72 100644 --- a/drivers/ports.h +++ b/drivers/ports.h @@ -53,3 +53,7 @@ typedef Port<0x3f8, uint8_t> com1_port_t; typedef Port<0x2f8, uint8_t> com2_port_t; typedef Port<0x3e8, uint8_t> com3_port_t; typedef Port<0x2e8, uint8_t> com4_port_t; + +/* 8259 PIC */ +typedef Port<0x20, uint8_t> pic1_t; +typedef Port<0xA0, uint8_t> pic2_t; diff --git a/libk/types.h b/libk/types.h index 599f852..08d42b9 100644 --- a/libk/types.h +++ b/libk/types.h @@ -13,6 +13,15 @@ typedef short int16_t; typedef int int32_t; typedef long long int int64_t; +/* in x86: + * byte: 1 byte, 8 bits + * word: 2 bytes, 16 bits + * dword: 4 bytes, 32 bits + * qword: 8 bytes, 64 bits + * */ +typedef uint16_t uword_t; +typedef int16_t word_t; + // Type Traits template diff --git a/src/idt.cc b/src/idt.cc new file mode 100644 index 0000000..fe4c159 --- /dev/null +++ b/src/idt.cc @@ -0,0 +1,51 @@ +#include "idt.h" +#include +#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); + +/* reinitialize the PIC controllers, giving them specified vector offsets + rather than 8h and 70h, as configured by default */ + +#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) */ + +IDT::IDT() { + 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(ICW4_8086, 0x1); + pic2.write(ICW4_8086, 0x1); + + pic1.write(mask1); + pic2.write(mask2); + + table[32] = Entry((unsigned long)kirq<0x0>, 0x08, InterruptGate); + table[33] = Entry((unsigned long)kirq<0x1>, 0x08, InterruptGate); + + Pointer ptr{.limit = sizeof(table), .base = (uint32_t)table}; + asm volatile("lidt %0" : : "m"(ptr)); + + printk("IDT installed at ", (uint32_t)table, '\n'); +} diff --git a/src/idt.h b/src/idt.h new file mode 100644 index 0000000..3aa5a1e --- /dev/null +++ b/src/idt.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +class IDT { +public: + struct Pointer { + uint16_t limit; + uint32_t base; + } __attribute__((packed)); + + 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 + }; + + class Entry { + public: + Entry(uint32_t offset = 0, uint16_t select = 0, InterruptType t = Null) { + offset_0_15 = offset & 0xffff; + offset_16_31 = (offset & 0xffff0000) >> 16; + selector = select; + type = t; + } + + private: + uint16_t offset_0_15; // 0-15 offset in the segment + uint16_t selector; // 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 + uint8_t dpl : 2 = 0; // 45-46 descriptor privilege level + [[maybe_unused]] bool e : 1 = true; // 47 enable + uint16_t offset_16_31; // 48-63 offset high + } __attribute__((packed)); + + IDT(); + +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 new file mode 100644 index 0000000..acd57d4 --- /dev/null +++ b/src/irq/kirq.cc @@ -0,0 +1,21 @@ +#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 1139e3b..7aaaa37 100644 --- a/src/kernel.cc +++ b/src/kernel.cc @@ -12,6 +12,7 @@ #include #include "cga.h" #include "gdt.h" +#include "idt.h" #include "serial.h" extern "C" { @@ -38,6 +39,8 @@ void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t m GDT gdt; dump_gdt(); - abort(); + IDT idt; + + // abort(); } } // extern "C" diff --git a/src/makefile b/src/makefile index 8214d03..ab08ee2 100644 --- a/src/makefile +++ b/src/makefile @@ -5,4 +5,6 @@ CXX_OBJ += src/kernel.o \ src/kernel/dump_multiboot.o \ src/memory.o \ src/gdt.o \ - src/gdt/segmentdescriptor.o + src/gdt/segmentdescriptor.o \ + src/idt.o \ + src/irq/kirq.o -- cgit v1.2.1