From ce47326682a5e17eb6bda2d6f32e3fb303792455 Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Tue, 2 Jun 2026 20:17:17 +0200 Subject: [PATCH 1/4] Added GDT support --- CMakeLists.txt | 33 +++++++++++++++------------- README.md | 2 +- include/core/gdt.h | 41 +++++++++++++++++++++++++++++++++++ include/core/systems.h | 17 +++++++++++++++ include/types.h | 1 + kernel/core/gdt/gdt.cpp | 35 ++++++++++++++++++++++++++++++ kernel/core/gdt/gdt_flush.asm | 26 ++++++++++++++++++++++ kernel/core/systems.cpp | 17 +++++++++++++++ kernel/main.cpp | 5 ++--- 9 files changed, 158 insertions(+), 19 deletions(-) create mode 100644 include/core/gdt.h create mode 100644 include/core/systems.h create mode 100644 kernel/core/gdt/gdt.cpp create mode 100644 kernel/core/gdt/gdt_flush.asm create mode 100644 kernel/core/systems.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2abb58f..be3f4fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.25) -project(Avery LANGUAGES CXX) +project(Avery LANGUAGES CXX ASM_NASM) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -10,8 +10,11 @@ set(ISO_ROOT ${CMAKE_BINARY_DIR}/iso) set(ISO_FILE ${CMAKE_BINARY_DIR}/avery.iso) set(LIMINE_DIR ${CMAKE_BINARY_DIR}/limine) +set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64) + file(GLOB_RECURSE KERNEL_SOURCES CONFIGURE_DEPENDS kernel/*.cpp + kernel/*.asm include/*.h include/*.hpp ) @@ -27,20 +30,20 @@ target_include_directories(avery_objects PRIVATE ) target_compile_options(avery_objects PRIVATE - -ffreestanding - -fno-exceptions - -fno-rtti - -fno-stack-protector - -fno-pic - -m64 - -mno-red-zone - -mcmodel=kernel - -Wall - -Wextra - -Wpedantic - -Wconversion - -Wshadow - -Werror + $<$:-ffreestanding> + $<$:-fno-exceptions> + $<$:-fno-rtti> + $<$:-fno-stack-protector> + $<$:-fno-pic> + $<$:-m64> + $<$:-mno-red-zone> + $<$:-mcmodel=kernel> + $<$:-Wall> + $<$:-Wextra> + $<$:-Wpedantic> + $<$:-Wconversion> + $<$:-Wshadow> + $<$:-Werror> ) set(KERNEL_ELF ${CMAKE_BINARY_DIR}/avery.elf) diff --git a/README.md b/README.md index 9499567..13d4af1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ practices while remaining approachable to contributors and learners alike. - [x] Framebuffer abstraction + character output - [x] Panic functions + Assertion system - [x] Logging system (both visual + serial) -- [ ] Halt loop +- [x] Halt loop - [ ] Basics of the kernel + GDT, IDT and interrupt handlers - [ ] PIC, timer and keyboard support - [ ] Stack tracing support diff --git a/include/core/gdt.h b/include/core/gdt.h new file mode 100644 index 0000000..96f32f4 --- /dev/null +++ b/include/core/gdt.h @@ -0,0 +1,41 @@ +/* +* gdt.h +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Managers for the Global Descriptor Table +* Copyright (c) 2026 Max Van den Eynde +*/ + +#ifndef AVERY_GDT_H +#define AVERY_GDT_H +#include "../types.h" + +#pragma once + +struct GDTEntry { + u16 limit_low; + u16 base_low; + u8 base_middle; + u8 access; + u8 granularity; + u8 base_high; +} __attribute__((packed)); + +struct GDTPtr { + u16 limit; + uptr base; +} __attribute__((packed)); + +// Defined in assembly +extern "C" void gdt_flush(); + +namespace core { + void initGdt(); +} + +namespace gdt { + void setGate(i32 num, u64 base, u64 limit, u8 access, u8 granularity); +} + +#endif //AVERY_GDT_H diff --git a/include/core/systems.h b/include/core/systems.h new file mode 100644 index 0000000..f38e687 --- /dev/null +++ b/include/core/systems.h @@ -0,0 +1,17 @@ +/* +* systems.h +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: ${FILE_DESCRIPTION} +* Copyright (c) 2026 Max Van den Eynde +*/ + +#ifndef AVERY_SYSTEMS_H +#define AVERY_SYSTEMS_H + +namespace core { + void initSystems(); +} + +#endif //AVERY_SYSTEMS_H diff --git a/include/types.h b/include/types.h index 64f46e6..08a717e 100644 --- a/include/types.h +++ b/include/types.h @@ -15,6 +15,7 @@ using u16 = unsigned short; using u32 = unsigned int; using u64 = unsigned long long; using usize = decltype(sizeof(0)); +using uptr = decltype(sizeof(0)); using i8 = char; using i16 = short; diff --git a/kernel/core/gdt/gdt.cpp b/kernel/core/gdt/gdt.cpp new file mode 100644 index 0000000..5dbd59f --- /dev/null +++ b/kernel/core/gdt/gdt.cpp @@ -0,0 +1,35 @@ +/* +* gdt.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Global Descriptor Table implementations +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +GDTEntry gdtEntries[3]; +GDTPtr gp; + +void gdt::setGate(i32 num, u64 base, u64 limit, u8 access, u8 granularity) { + gdtEntries[num].base_low = (base & 0xFFFF); + gdtEntries[num].base_middle = (base >> 16) & 0xFF; + gdtEntries[num].base_high = (base >> 24) & 0xFF; + + gdtEntries[num].limit_low = (limit & 0xFFFF); + gdtEntries[num].granularity = (limit >> 16) & 0x0F; + + gdtEntries[num].granularity |= (granularity & 0xF0); + gdtEntries[num].access = access; +} + +void core::initGdt() { + gp.limit = (sizeof(GDTEntry) * 3) - 1; + gp.base = reinterpret_cast(&gdtEntries); + + gdt::setGate(0, 0, 0, 0, 0); + gdt::setGate(1, 0, 0xFFFFFFFF, 0x9A, 0xA0); + gdt::setGate(2, 0, 0xFFFFFFFF, 0x92, 0xC0); + gdt_flush(); +} diff --git a/kernel/core/gdt/gdt_flush.asm b/kernel/core/gdt/gdt_flush.asm new file mode 100644 index 0000000..fbebe3e --- /dev/null +++ b/kernel/core/gdt/gdt_flush.asm @@ -0,0 +1,26 @@ +; +; gdt_flush.asm +; Created by Maxims Enterprise +; in 2026 as part of the Avery project +; + +bits 64 + +global gdt_flush +extern gp + +gdt_flush: + lgdt [rel gp] + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov ss, ax + + push qword 0x08 + lea rax, [rel .flush] + push rax + retfq + +.flush: + ret \ No newline at end of file diff --git a/kernel/core/systems.cpp b/kernel/core/systems.cpp new file mode 100644 index 0000000..d83a2eb --- /dev/null +++ b/kernel/core/systems.cpp @@ -0,0 +1,17 @@ +/* +* systems.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Core Kernel systems +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include +#include "kernel/debug.h" +#include + +void core::initSystems() { + initGdt(); + debug::log("Initialized GDT"); +} diff --git a/kernel/main.cpp b/kernel/main.cpp index ff39692..e53a923 100644 --- a/kernel/main.cpp +++ b/kernel/main.cpp @@ -2,6 +2,7 @@ #include "../include/kernel/console.h" #include "core/regs.h" +#include "core/systems.h" #include "graphics/framebuffer.h" #include "io/serial.h" #include "kernel/debug.h" @@ -24,6 +25,7 @@ static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARK extern "C" [[noreturn]] void _start() { regs::enableSSE(); + core::initSystems(); if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { while (true) { @@ -35,9 +37,6 @@ extern "C" [[noreturn]] void _start() { Framebuffer framebuffer = Framebuffer::createFromLimineRequest(framebuffer_request); out::initFramebufferConsole(framebuffer); - ASSERT(false == true); - - out::println("Hello, World!"); out::switchTo(ConsoleOutputMode::Serial); out::println("Hello, World!"); From 95c60464d79e335c43cb6c6fdd9b616e59c2e307 Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Tue, 2 Jun 2026 20:34:36 +0200 Subject: [PATCH 2/4] Added IDT support --- include/core/idt.h | 42 +++++++++++++++++++++++++++++++++ include/kernel/memory.h | 25 ++++++++++++++++++++ kernel/core/idt/idt.cpp | 35 +++++++++++++++++++++++++++ kernel/core/idt/idt_load.asm | 11 +++++++++ kernel/core/memory/memory.cpp | 16 +++++++++++++ kernel/core/systems.cpp | 4 ++++ kernel/graphics/framebuffer.cpp | 2 +- kernel/main.cpp | 6 ++--- 8 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 include/core/idt.h create mode 100644 include/kernel/memory.h create mode 100644 kernel/core/idt/idt.cpp create mode 100644 kernel/core/idt/idt_load.asm create mode 100644 kernel/core/memory/memory.cpp diff --git a/include/core/idt.h b/include/core/idt.h new file mode 100644 index 0000000..f68f715 --- /dev/null +++ b/include/core/idt.h @@ -0,0 +1,42 @@ +/* +* idt.h +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: ${FILE_DESCRIPTION} +* Copyright (c) 2026 Max Van den Eynde +*/ + +#ifndef AVERY_IDT_H +#define AVERY_IDT_H + +#pragma once +#include "../types.h" + +struct IDTEntry { + u16 offsetLow; + u16 selector; + u8 ist; + u8 flags; + u16 offsetMid; + u32 offsetHigh; + u32 zero; +} __attribute__((packed)); + +struct IDTPtr { + u16 limit; + uptr base; +} __attribute__((packed)); + +extern "C" void idt_load(); + +namespace core { + void initIdt(); +} + +namespace idt { + void setGate(u8 num, u64 base, u16 sel, u8 flags); +} + + +#endif //AVERY_IDT_H diff --git a/include/kernel/memory.h b/include/kernel/memory.h new file mode 100644 index 0000000..d13887a --- /dev/null +++ b/include/kernel/memory.h @@ -0,0 +1,25 @@ +/* +* memory.h +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Memory related functions +* Copyright (c) 2026 Max Van den Eynde +*/ + +#ifndef AVERY_MEMORY_H +#define AVERY_MEMORY_H +#include "../types.h" + +namespace memory { + void copy(u8* dest, const u8* src, int count); + + template + void set(T* dest, T val, int count) { + for (int i = 0; i < count; i++) { + dest[i] = val; + } + } +} + +#endif //AVERY_MEMORY_H diff --git a/kernel/core/idt/idt.cpp b/kernel/core/idt/idt.cpp new file mode 100644 index 0000000..34754c7 --- /dev/null +++ b/kernel/core/idt/idt.cpp @@ -0,0 +1,35 @@ +/* +* idt.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Idt-related function implementation +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +#include "kernel/memory.h" + +IDTEntry idtEntries[256]; +IDTPtr idtp; + +void idt::setGate(u8 num, u64 base, u16 sel, u8 flags) { + idtEntries[num].offsetLow = (base & 0xFFFF); + idtEntries[num].selector = sel; + idtEntries[num].ist = 0; + idtEntries[num].flags = flags; + idtEntries[num].offsetMid = (base >> 16) & 0xFFFF; + idtEntries[num].offsetHigh = (base >> 16) & 0xFFFF; + idtEntries[num].zero = 0; +} + +void core::initIdt() { + idtp.limit = (sizeof(IDTEntry) * 256) - 1; + idtp.base = reinterpret_cast(&idtEntries); + + memory::set(reinterpret_cast(&idtEntries), 0, sizeof(IDTEntry) * 256); + + idt_load(); +} + diff --git a/kernel/core/idt/idt_load.asm b/kernel/core/idt/idt_load.asm new file mode 100644 index 0000000..cfcc933 --- /dev/null +++ b/kernel/core/idt/idt_load.asm @@ -0,0 +1,11 @@ +; +; idt_load.asm +; Created by Maxims Enterprise +; in 2026 as part of the Avery project +; + +global idt_load +extern idtp +idt_load: + lidt [rel idtp] + ret \ No newline at end of file diff --git a/kernel/core/memory/memory.cpp b/kernel/core/memory/memory.cpp new file mode 100644 index 0000000..b54e6ff --- /dev/null +++ b/kernel/core/memory/memory.cpp @@ -0,0 +1,16 @@ +/* +* memory.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Memory functions implementation +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +void memory::copy(u8* dest, const u8* src, int count) { + for (int i = 0; i < count; i++) { + dest[i] = src[i]; + } +} diff --git a/kernel/core/systems.cpp b/kernel/core/systems.cpp index d83a2eb..94c2886 100644 --- a/kernel/core/systems.cpp +++ b/kernel/core/systems.cpp @@ -11,7 +11,11 @@ #include "kernel/debug.h" #include +#include "core/idt.h" + void core::initSystems() { initGdt(); debug::log("Initialized GDT"); + initIdt(); + debug::log("Initialized IDT"); } diff --git a/kernel/graphics/framebuffer.cpp b/kernel/graphics/framebuffer.cpp index b6aedb7..cded0f4 100644 --- a/kernel/graphics/framebuffer.cpp +++ b/kernel/graphics/framebuffer.cpp @@ -67,7 +67,7 @@ Framebuffer Framebuffer::createFromLimineRequest( ) { Framebuffer framebuffer; - ASSERT(request.response == nullptr || request.response->framebuffer_count < 1); + ASSERT(request.response != nullptr && request.response->framebuffer_count >= 1); framebuffer.fb = request.response->framebuffers[0]; framebuffer.fb_ptr = static_cast(framebuffer.fb->address); diff --git a/kernel/main.cpp b/kernel/main.cpp index e53a923..e61b56b 100644 --- a/kernel/main.cpp +++ b/kernel/main.cpp @@ -37,9 +37,9 @@ extern "C" [[noreturn]] void _start() { Framebuffer framebuffer = Framebuffer::createFromLimineRequest(framebuffer_request); out::initFramebufferConsole(framebuffer); - out::println("Hello, World!"); - out::switchTo(ConsoleOutputMode::Serial); - out::println("Hello, World!"); + out::println("The Avery Kernel"); + out::println("Version Alpha 1 (Development Edition)"); + out::println("Made by Neutral Software in 2026"); while (true) { asm("hlt"); From f7f982c007bf85a6bcaf783f0114a59e40590586 Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Tue, 2 Jun 2026 21:11:31 +0200 Subject: [PATCH 3/4] Added support for ISRs --- README.md | 2 +- include/core/isr.h | 69 ++++++++++++++++ include/kernel/console.h | 1 + kernel/core/debug.cpp | 12 +-- kernel/core/idt/idt.cpp | 2 +- kernel/core/isrs/isr.cpp | 93 ++++++++++++++++++++++ kernel/core/isrs/isr_stubs.asm | 140 +++++++++++++++++++++++++++++++++ kernel/core/systems.cpp | 3 + kernel/io/console.cpp | 15 ++++ 9 files changed, 329 insertions(+), 8 deletions(-) create mode 100644 include/core/isr.h create mode 100644 kernel/core/isrs/isr.cpp create mode 100644 kernel/core/isrs/isr_stubs.asm diff --git a/README.md b/README.md index 13d4af1..b043a41 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ practices while remaining approachable to contributors and learners alike. ### Memory -- [ ] Limine Memory map parsion +- [ ] Limine Memory map parsing - [ ] Physical memory manager - [ ] Virtual memory manager - [ ] Kernel heap (malloc, free) diff --git a/include/core/isr.h b/include/core/isr.h new file mode 100644 index 0000000..56270df --- /dev/null +++ b/include/core/isr.h @@ -0,0 +1,69 @@ +/* +* isr.h +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Interrupt Subroutines +* Copyright (c) 2026 Max Van den Eynde +*/ + +#ifndef AVERY_ISR_H +#define AVERY_ISR_H + +#define ISR_EXTERN_FUNCTION(N) extern "C" void isr##N() +#include "../types.h" + +namespace isr { + ISR_EXTERN_FUNCTION(0); + ISR_EXTERN_FUNCTION(1); + ISR_EXTERN_FUNCTION(2); + ISR_EXTERN_FUNCTION(3); + ISR_EXTERN_FUNCTION(4); + ISR_EXTERN_FUNCTION(5); + ISR_EXTERN_FUNCTION(6); + ISR_EXTERN_FUNCTION(7); + ISR_EXTERN_FUNCTION(8); + ISR_EXTERN_FUNCTION(9); + ISR_EXTERN_FUNCTION(10); + ISR_EXTERN_FUNCTION(11); + ISR_EXTERN_FUNCTION(12); + ISR_EXTERN_FUNCTION(13); + ISR_EXTERN_FUNCTION(14); + ISR_EXTERN_FUNCTION(15); + ISR_EXTERN_FUNCTION(16); + ISR_EXTERN_FUNCTION(17); + ISR_EXTERN_FUNCTION(18); + ISR_EXTERN_FUNCTION(19); + ISR_EXTERN_FUNCTION(20); + ISR_EXTERN_FUNCTION(21); + ISR_EXTERN_FUNCTION(22); + ISR_EXTERN_FUNCTION(23); + ISR_EXTERN_FUNCTION(24); + ISR_EXTERN_FUNCTION(25); + ISR_EXTERN_FUNCTION(26); + ISR_EXTERN_FUNCTION(27); + ISR_EXTERN_FUNCTION(28); + ISR_EXTERN_FUNCTION(29); + ISR_EXTERN_FUNCTION(30); + ISR_EXTERN_FUNCTION(31); + + struct Registers { + u64 r15, r14, r13, r12, r11, r10, r9, r8; + u64 rsi, rdi, rbp, rdx, rcx, rbx, rax; + u64 int_no; + u64 err_code; + u64 rip; + u64 cs; + u64 rflags; + u64 rsp; + u64 ss; + }; + + void fault_handler(Registers* regs); +}; + +namespace core { + void initIsrs(); +} + +#endif //AVERY_ISR_H diff --git a/include/kernel/console.h b/include/kernel/console.h index 3b1615f..946915d 100644 --- a/include/kernel/console.h +++ b/include/kernel/console.h @@ -29,6 +29,7 @@ namespace out { void initFramebufferConsole(const Framebuffer& framebuffer); void print(string str); void println(string str); + void printHex(u64 num); void putChar(char c); void clear(); diff --git a/kernel/core/debug.cpp b/kernel/core/debug.cpp index cb33e1a..3b8e829 100644 --- a/kernel/core/debug.cpp +++ b/kernel/core/debug.cpp @@ -40,13 +40,13 @@ void debug::log(const char* message, LogType logType) { if (logType == LogType::Serial) { - io::serialWrite("(LOG) -> "); + io::serialWrite("[LOG] "); io::serialWrite(message); io::serialWrite("\n"); } else { out::setColor(Color::green, Color::black); - out::print("(LOG): "); + out::print("[LOG]"); out::println(message); } } @@ -54,13 +54,13 @@ void debug::log(const char* message, LogType logType) { void debug::warn(const char* message, LogType logType) { if (logType == LogType::Serial) { - io::serialWrite("(WARNING) -> "); + io::serialWrite("[WARNING] "); io::serialWrite(message); io::serialWrite("\n"); } else { out::setColor(Color::yellow, Color::black); - out::print("(WARNING): "); + out::print("[WARNING] "); out::println(message); } } @@ -68,13 +68,13 @@ void debug::warn(const char* message, LogType logType) { void debug::error(const char* message, LogType logType) { if (logType == LogType::Serial) { - io::serialWrite("(ERROR) -> "); + io::serialWrite("[ERROR] "); io::serialWrite(message); io::serialWrite("\n"); } else { out::setColor(Color::red, Color::black); - out::print("(ERROR): "); + out::print("[ERROR] "); out::println(message); } } diff --git a/kernel/core/idt/idt.cpp b/kernel/core/idt/idt.cpp index 34754c7..80bdc24 100644 --- a/kernel/core/idt/idt.cpp +++ b/kernel/core/idt/idt.cpp @@ -20,7 +20,7 @@ void idt::setGate(u8 num, u64 base, u16 sel, u8 flags) { idtEntries[num].ist = 0; idtEntries[num].flags = flags; idtEntries[num].offsetMid = (base >> 16) & 0xFFFF; - idtEntries[num].offsetHigh = (base >> 16) & 0xFFFF; + idtEntries[num].offsetHigh = (base >> 32) & 0xFFFFFFFF; idtEntries[num].zero = 0; } diff --git a/kernel/core/isrs/isr.cpp b/kernel/core/isrs/isr.cpp new file mode 100644 index 0000000..8886c3e --- /dev/null +++ b/kernel/core/isrs/isr.cpp @@ -0,0 +1,93 @@ +/* +* isr.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: ISR binding and definition +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include "types.h" +#include "core/isr.h" + +#include "core/idt.h" +#include "kernel/console.h" +#include "kernel/debug.h" + +string exception_messages[] = { + "Division By Zero Exception", + "Debug Exception", + "Non Maskable Interrupt Exception", + "Breakpoint Exception", + "Into Detected Overflow Exception", + "Out of Bounds Exception", + "Invalid Opcode Exception", + "No Coprocessor Exception", + "Double Fault Exception", + "Coprocessor Segment Overrun Exception", + "Bad TSS Exception", + "Segment Not Present Exception", + "Stack Fault Exception", + "General Protection Fault Exception", + "Page Fault Exception", + "Unknown Interrupt Exception", + "Coprocessor Fault Exception", + "Alignment Check Exception (486+)", + "Machine Check Exception (Pentium/586+)", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +void core::initIsrs() { + idt::setGate(0, reinterpret_cast(isr::isr0), 0x08, 0x8E); + idt::setGate(1, reinterpret_cast(isr::isr1), 0x08, 0x8E); + idt::setGate(2, reinterpret_cast(isr::isr2), 0x08, 0x8E); + idt::setGate(3, reinterpret_cast(isr::isr3), 0x08, 0x8E); + idt::setGate(4, reinterpret_cast(isr::isr4), 0x08, 0x8E); + idt::setGate(5, reinterpret_cast(isr::isr5), 0x08, 0x8E); + idt::setGate(6, reinterpret_cast(isr::isr6), 0x08, 0x8E); + idt::setGate(7, reinterpret_cast(isr::isr7), 0x08, 0x8E); + idt::setGate(8, reinterpret_cast(isr::isr8), 0x08, 0x8E); + idt::setGate(9, reinterpret_cast(isr::isr9), 0x08, 0x8E); + idt::setGate(10, reinterpret_cast(isr::isr10), 0x08, 0x8E); + idt::setGate(11, reinterpret_cast(isr::isr11), 0x08, 0x8E); + idt::setGate(12, reinterpret_cast(isr::isr12), 0x08, 0x8E); + idt::setGate(13, reinterpret_cast(isr::isr13), 0x08, 0x8E); + idt::setGate(14, reinterpret_cast(isr::isr14), 0x08, 0x8E); + idt::setGate(15, reinterpret_cast(isr::isr15), 0x08, 0x8E); + idt::setGate(16, reinterpret_cast(isr::isr16), 0x08, 0x8E); + idt::setGate(17, reinterpret_cast(isr::isr17), 0x08, 0x8E); + idt::setGate(18, reinterpret_cast(isr::isr18), 0x08, 0x8E); + idt::setGate(19, reinterpret_cast(isr::isr19), 0x08, 0x8E); + idt::setGate(20, reinterpret_cast(isr::isr20), 0x08, 0x8E); + idt::setGate(21, reinterpret_cast(isr::isr21), 0x08, 0x8E); + idt::setGate(22, reinterpret_cast(isr::isr22), 0x08, 0x8E); + idt::setGate(23, reinterpret_cast(isr::isr23), 0x08, 0x8E); + idt::setGate(24, reinterpret_cast(isr::isr24), 0x08, 0x8E); + idt::setGate(25, reinterpret_cast(isr::isr25), 0x08, 0x8E); + idt::setGate(26, reinterpret_cast(isr::isr26), 0x08, 0x8E); + idt::setGate(27, reinterpret_cast(isr::isr27), 0x08, 0x8E); + idt::setGate(28, reinterpret_cast(isr::isr28), 0x08, 0x8E); + idt::setGate(29, reinterpret_cast(isr::isr29), 0x08, 0x8E); + idt::setGate(30, reinterpret_cast(isr::isr30), 0x08, 0x8E); + idt::setGate(31, reinterpret_cast(isr::isr31), 0x08, 0x8E); +} + +extern "C" void fault_handler(isr::Registers* regs) { + if (regs->int_no < 32) { + out::print("Panic with error code: "); + out::printHex(regs->err_code); + PANIC(exception_messages[regs->int_no]); + } +} diff --git a/kernel/core/isrs/isr_stubs.asm b/kernel/core/isrs/isr_stubs.asm new file mode 100644 index 0000000..778c844 --- /dev/null +++ b/kernel/core/isrs/isr_stubs.asm @@ -0,0 +1,140 @@ +; +; isr_stubs.asm +; Created by Maxims Enterprise +; in 2026 as part of the Avery project +; + +; global isrN (name) (has error code?) +global isr0 ; divide by zero (no) +global isr1 ; debug exception (no) +global isr2 ; non maskable interrupt (no) +global isr3 ; breakpoint (no) +global isr4 ; into detected overflow (no) +global isr5 ; out of bounds (no) +global isr6 ; invalid opcode (no) +global isr7 ; no coprocessor (no) +global isr8 ; double fault exception (yes) +global isr9 ; coprocessor segment overrun (no) +global isr10 ; bad tss (yes) +global isr11 ; segment not present (yes) +global isr12 ; stack fault (yes) +global isr13 ; general protection fault (yes) +global isr14 ; page fault exception (yes) +global isr15 ; unknown interrupt (no) +global isr16 ; coprocessor fault exception (no) +global isr17 ; alignment check (no) +global isr18 ; machine check (no) +global isr19 ; reserved up to 31 +global isr20 +global isr21 +global isr22 +global isr23 +global isr24 +global isr25 +global isr26 +global isr27 +global isr28 +global isr29 +global isr30 +global isr31 + +extern fault_handler + +%macro ISR_NOERR 1 +global isr%1 +isr%1: + cli + push qword 0 + push qword %1 + jmp isr_common_stub +%endmacro + +%macro ISR_ERR 1 +global isr%1 +isr%1: + cli + push qword %1 + jmp isr_common_stub +%endmacro + +ISR_NOERR 0 +ISR_NOERR 1 +ISR_NOERR 2 +ISR_NOERR 3 +ISR_NOERR 4 +ISR_NOERR 5 +ISR_NOERR 6 +ISR_NOERR 7 +ISR_ERR 8 +ISR_NOERR 9 +ISR_ERR 10 +ISR_ERR 11 +ISR_ERR 12 +ISR_ERR 13 +ISR_ERR 14 +ISR_NOERR 15 +ISR_NOERR 16 +ISR_ERR 17 +ISR_NOERR 18 +ISR_NOERR 19 +ISR_NOERR 20 +ISR_ERR 21 +ISR_NOERR 22 +ISR_NOERR 23 +ISR_NOERR 24 +ISR_NOERR 25 +ISR_NOERR 26 +ISR_NOERR 27 +ISR_NOERR 28 +ISR_ERR 29 +ISR_ERR 30 +ISR_NOERR 31 + +isr_common_stub: + push rax + push rbx + push rcx + push rdx + push rbp + push rdi + push rsi + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + mov rdi, rsp + call fault_handler + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rdi + pop rbp + pop rdx + pop rcx + pop rbx + pop rax + + add rsp, 16 + iretq + + + + + + + + + + + diff --git a/kernel/core/systems.cpp b/kernel/core/systems.cpp index 94c2886..99b4aba 100644 --- a/kernel/core/systems.cpp +++ b/kernel/core/systems.cpp @@ -12,10 +12,13 @@ #include #include "core/idt.h" +#include "core/isr.h" void core::initSystems() { initGdt(); debug::log("Initialized GDT"); initIdt(); debug::log("Initialized IDT"); + initIsrs(); + debug::log("All ISRs bound correctly"); } diff --git a/kernel/io/console.cpp b/kernel/io/console.cpp index 946ad36..ae11de4 100644 --- a/kernel/io/console.cpp +++ b/kernel/io/console.cpp @@ -74,3 +74,18 @@ void out::putChar(char c) { io::serialWriteChar(c); } } + +void out::printHex(u64 num) { + char hex[17]; // 16 digits + null terminator + hex[16] = '\0'; + + const char* digits = "0123456789ABCDEF"; + + for (int i = 15; i >= 0; --i) { + hex[i] = digits[num & 0xF]; + num >>= 4; + } + + print("0x"); + print(hex); +} From 8c98341eabc986e31e91f7f0ee432ec23fa90a43 Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Tue, 2 Jun 2026 21:20:26 +0200 Subject: [PATCH 4/4] Added IRQ support --- README.md | 2 +- include/core/irq.h | 48 +++++++++++++++++++++++ kernel/core/irqs/irq.cpp | 72 +++++++++++++++++++++++++++++++++++ kernel/core/irqs/irq_stub.asm | 72 +++++++++++++++++++++++++++++++++++ kernel/core/systems.cpp | 3 ++ 5 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 include/core/irq.h create mode 100644 kernel/core/irqs/irq.cpp create mode 100644 kernel/core/irqs/irq_stub.asm diff --git a/README.md b/README.md index b043a41..0cff893 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ practices while remaining approachable to contributors and learners alike. - [x] Panic functions + Assertion system - [x] Logging system (both visual + serial) - [x] Halt loop -- [ ] Basics of the kernel + GDT, IDT and interrupt handlers +- [x] Basics of the kernel + GDT, IDT and interrupt handlers - [ ] PIC, timer and keyboard support - [ ] Stack tracing support diff --git a/include/core/irq.h b/include/core/irq.h new file mode 100644 index 0000000..a9fdf3a --- /dev/null +++ b/include/core/irq.h @@ -0,0 +1,48 @@ +/* +* irq.h +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Interrupt Requests handler +* Copyright (c) 2026 Max Van den Eynde +*/ + +#ifndef AVERY_IRQ_H +#define AVERY_IRQ_H + +#define IRQ_EXTERN_FUNCTION(N) extern "C" void irq##N() +#include "isr.h" + +namespace irq { + IRQ_EXTERN_FUNCTION(0); + IRQ_EXTERN_FUNCTION(1); + IRQ_EXTERN_FUNCTION(2); + IRQ_EXTERN_FUNCTION(3); + IRQ_EXTERN_FUNCTION(4); + IRQ_EXTERN_FUNCTION(5); + IRQ_EXTERN_FUNCTION(6); + IRQ_EXTERN_FUNCTION(7); + IRQ_EXTERN_FUNCTION(8); + IRQ_EXTERN_FUNCTION(9); + IRQ_EXTERN_FUNCTION(10); + IRQ_EXTERN_FUNCTION(11); + IRQ_EXTERN_FUNCTION(12); + IRQ_EXTERN_FUNCTION(13); + IRQ_EXTERN_FUNCTION(14); + IRQ_EXTERN_FUNCTION(15); + + using IRQHandler = void (*)(isr::Registers*); + + void installHandler(int irq, IRQHandler); + void uninstallHandler(int irq); + void remap(); +} + +namespace core { + void initIrq(); +} + +extern "C" void irq_handler(isr::Registers* regs); + + +#endif //AVERY_IRQ_H diff --git a/kernel/core/irqs/irq.cpp b/kernel/core/irqs/irq.cpp new file mode 100644 index 0000000..83bd939 --- /dev/null +++ b/kernel/core/irqs/irq.cpp @@ -0,0 +1,72 @@ +/* +* irq.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Interrupt Requests +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include "core/irq.h" + +#include "core/idt.h" +#include "io/io.h" + +irq::IRQHandler irq_routines[16] = { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr +}; + +void irq::installHandler(int irq, IRQHandler handler) { + irq_routines[irq] = handler; +} + +void irq::uninstallHandler(int irq) { + irq_routines[irq] = nullptr; +} + +void irq::remap() { + io::outb(0x20, 0x11); + io::outb(0xA0, 0x11); + io::outb(0x21, 0x20); + io::outb(0xA1, 0x28); + io::outb(0x21, 0x04); + io::outb(0xA1, 0x02); + io::outb(0x21, 0x01); + io::outb(0xA1, 0x01); + io::outb(0x21, 0x0); + io::outb(0xA1, 0x0); +} + +void core::initIrq() { + irq::remap(); + + idt::setGate(32, reinterpret_cast(irq::irq0), 0x08, 0x8E); + idt::setGate(33, reinterpret_cast(irq::irq1), 0x08, 0x8E); + idt::setGate(34, reinterpret_cast(irq::irq2), 0x08, 0x8E); + idt::setGate(35, reinterpret_cast(irq::irq3), 0x08, 0x8E); + idt::setGate(36, reinterpret_cast(irq::irq4), 0x08, 0x8E); + idt::setGate(37, reinterpret_cast(irq::irq5), 0x08, 0x8E); + idt::setGate(38, reinterpret_cast(irq::irq6), 0x08, 0x8E); + idt::setGate(39, reinterpret_cast(irq::irq7), 0x08, 0x8E); + idt::setGate(40, reinterpret_cast(irq::irq8), 0x08, 0x8E); + idt::setGate(41, reinterpret_cast(irq::irq9), 0x08, 0x8E); + idt::setGate(42, reinterpret_cast(irq::irq10), 0x08, 0x8E); + idt::setGate(43, reinterpret_cast(irq::irq11), 0x08, 0x8E); + idt::setGate(44, reinterpret_cast(irq::irq12), 0x08, 0x8E); + idt::setGate(45, reinterpret_cast(irq::irq13), 0x08, 0x8E); + idt::setGate(46, reinterpret_cast(irq::irq14), 0x08, 0x8E); + idt::setGate(47, reinterpret_cast(irq::irq15), 0x08, 0x8E); +} + +extern "C" void irq_handler(isr::Registers* regs) { + if (irq::IRQHandler handler = irq_routines[regs->int_no - 32]) { + handler(regs); + } + + if (regs->int_no >= 40) { + io::outb(0xA0, 0x20); + } + + io::outb(0x20, 0x20); +} diff --git a/kernel/core/irqs/irq_stub.asm b/kernel/core/irqs/irq_stub.asm new file mode 100644 index 0000000..77e2162 --- /dev/null +++ b/kernel/core/irqs/irq_stub.asm @@ -0,0 +1,72 @@ +; +; irq_stub.asm +; Created by Maxims Enterprise +; in 2026 as part of the Avery project +; + +%macro IRQ 2 +global irq%1 +irq%1: + cli + push qword 0 ; dummy error code + push qword %2 ; IDT interrupt number, 32-47 + jmp irq_common_stub +%endmacro + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +extern irq_handler + +irq_common_stub: + push rax + push rbx + push rcx + push rdx + push rbp + push rdi + push rsi + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + mov rdi, rsp + call irq_handler + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rsi + pop rdi + pop rbp + pop rdx + pop rcx + pop rbx + pop rax + + add rsp, 16 + iretq \ No newline at end of file diff --git a/kernel/core/systems.cpp b/kernel/core/systems.cpp index 99b4aba..dd1249e 100644 --- a/kernel/core/systems.cpp +++ b/kernel/core/systems.cpp @@ -12,6 +12,7 @@ #include #include "core/idt.h" +#include "core/irq.h" #include "core/isr.h" void core::initSystems() { @@ -21,4 +22,6 @@ void core::initSystems() { debug::log("Initialized IDT"); initIsrs(); debug::log("All ISRs bound correctly"); + initIrq(); + debug::log("All IRQs bound correctly"); }