From b7c0fdd686e6e412798b451210a0bfd3de23e31c Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Fri, 5 Jun 2026 11:06:14 +0200 Subject: [PATCH 1/4] Added inner driver support --- include/drivers/driver.h | 121 +++++++++++++++++++++++++++++++++++-- kernel/drivers/drivers.cpp | 103 +++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 kernel/drivers/drivers.cpp diff --git a/include/drivers/driver.h b/include/drivers/driver.h index 6d0a8ff..8d0a2fb 100644 --- a/include/drivers/driver.h +++ b/include/drivers/driver.h @@ -11,18 +11,127 @@ #define AVERY_DRIVER_H #include "../types.h" -using DriverInitFunction = void (*)(); +enum class DeviceType { + Unknown, + Block, + Character, + PCI, +}; + +enum class DriverState { + Created, + Registered, + Probing, + Active, + Failed, + Stopping, +}; + +class Driver; + +class Device { +public: + virtual ~Device() = default; + + Device(string name, DeviceType type) : deviceName(name), deviceType(type) { + } + + string name() const { return this->deviceName; } + DeviceType type() const { return this->deviceType; } + + Driver* driver = nullptr; + Device* parent = nullptr; + +private: + string deviceName; + DeviceType deviceType; +}; + +class BlockDevice : public Device { +public: + BlockDevice(string name, u64 blocks, u32 blockSize) + : Device(name, DeviceType::Block), deviceBlocks(blocks), deviceBlockSize(blockSize) { + } + + virtual bool readBlocks(u64 lba, u32 count, void* buffer) = 0; + virtual bool writeBlocks(u64 lba, u32 count, const void* buffer) = 0; + + u64 blockCount() const { return deviceBlocks; } + u64 blockSize() const { return deviceBlockSize; } + +private: + u64 deviceBlocks; + u32 deviceBlockSize; +}; + +class CharacterDevice : public Device { +public: + CharacterDevice(string name) : Device(name, DeviceType::Character) { + } -enum class DriverType { - Generic + virtual int read(u8* buffer, usize size) = 0; + virtual int write(const u8* buffer, usize size) = 0; +}; + +class PCIDevice : public Device { +public: + PCIDevice(string name, DeviceType type) : Device(name, type) { + } }; class Driver { public: - string name; - DriverType type; + Driver() = default; + virtual ~Driver() = default; + + Driver(const Driver&) = delete; + Driver& operator=(const Driver&) = delete; + + virtual string name() const = 0; + + virtual bool probe(Device& device) = 0; + virtual bool start(Device& device) = 0; + virtual bool stop(Device& device) = 0; + + DriverState state() const { + return driverState; + } + + void setState(DriverState state) { + driverState = state; + } + +private: + DriverState driverState = DriverState::Created; +}; + +class DeviceManager { +public: + static bool registerDevice(Device* device); + static void unregisterDevice(Device* device); + + static Device* deviceAt(usize index); + static usize deviceCount(); + +private: + static constexpr usize MaxDevices = 256; + static Device* devices[MaxDevices]; + static usize s_deviceCount; +}; + +class DriverManager { +public: + static bool registerDriver(Driver* driver); + static void unregisterDriver(Driver* driver); + + static bool tryBind(Device& device); + static bool tryBind(Driver& driver); + static void unbind(Device& device); - DriverInitFunction init; +private: + static constexpr usize MaxDrivers = 128; + static Driver* drivers[MaxDrivers]; + static usize driverCount; }; #endif //AVERY_DRIVER_H diff --git a/kernel/drivers/drivers.cpp b/kernel/drivers/drivers.cpp new file mode 100644 index 0000000..a4a5d15 --- /dev/null +++ b/kernel/drivers/drivers.cpp @@ -0,0 +1,103 @@ +/* +* drivers.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Driver manager +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +bool DeviceManager::registerDevice(Device* device) { + if (!device) { + return false; + } + + if (deviceCount() >= MaxDevices) { + return false; + } + + devices[s_deviceCount++] = device; + + DriverManager::tryBind(*device); + + return true; +} + +bool DriverManager::registerDriver(Driver* driver) { + if (!driver) { + return false; + } + + if (driverCount >= MaxDrivers) { + return false; + } + + drivers[driverCount++] = driver; + + tryBind(*driver); + return true; +} + +bool DriverManager::tryBind(Device& device) { + if (device.driver) { + return false; + } + + for (usize i = 0; i < driverCount; i++) { + Driver* driver = drivers[i]; + + if (!driver->probe(device)) continue; + if (!driver->start(device)) continue; + + device.driver = driver; + return true; + } + + return false; +} + +bool DriverManager::tryBind(Driver& driver) { + for (usize i = 0; i < DeviceManager::deviceCount(); i++) { + Device* device = DeviceManager::deviceAt(i); + + if (!device) continue; + if (device->driver) continue; + if (!driver.probe(*device)) continue; + if (!driver.start(*device)) continue; + + device->driver = &driver; + } + + return true; +} + +void DeviceManager::unregisterDevice(Device* device) { + if (!device) { + return; + } + + DriverManager::unbind(*device); + + for (usize i = 0; i < deviceCount(); i++) { + if (deviceAt(i) == device) { + for (usize j = i; j + 1 < deviceCount(); j++) { + devices[j] = devices[j + 1]; + } + + devices[s_deviceCount - 1] = nullptr; + s_deviceCount--; + return; + } + } +} + +void DriverManager::unbind(Device& device) { + Driver* driver = device.driver; + + if (!driver) return; + + driver->stop(device); + device.driver = nullptr; +} From 572ac8019feba11cb4b717116573c77447e09bad Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Fri, 5 Jun 2026 11:09:49 +0200 Subject: [PATCH 2/4] Moved keyboard and PIT to drivers --- README.md | 8 +-- include/drivers/driver.h | 6 ++ include/drivers/keyboard.h | 3 + include/drivers/pit.h | 3 + include/kernel/memory.h | 2 +- include/types.h | 1 + kernel/core/systems.cpp | 6 -- kernel/drivers/drivers.cpp | 92 +++++++++++++++++++++++++++++-- kernel/drivers/input/keyboard.cpp | 46 ++++++++++++++++ kernel/drivers/time/pit.cpp | 60 ++++++++++++++++++-- kernel/main.cpp | 4 +- kernel/utils/types.cpp | 6 ++ 12 files changed, 215 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index fc1e8f4..57c2900 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ practices while remaining approachable to contributors and learners alike. ### Internal Driver Framework -- [ ] Device objects -- [ ] Driver registration -- [ ] Driver lifecycle +- [x] Device objects +- [x] Driver registration +- [x] Driver lifecycle - [ ] MMIO port I/O helpers -- [ ] Block device abstraction +- [x] Block device abstraction - [ ] Move to Limine 6 barely (APIC or x2APIC mapped to legacy PIC) ### Hardware discovery diff --git a/include/drivers/driver.h b/include/drivers/driver.h index 8d0a2fb..a132dd2 100644 --- a/include/drivers/driver.h +++ b/include/drivers/driver.h @@ -15,6 +15,8 @@ enum class DeviceType { Unknown, Block, Character, + Timer, + Input, PCI, }; @@ -134,4 +136,8 @@ class DriverManager { static usize driverCount; }; +namespace drivers { + void init(); +} + #endif //AVERY_DRIVER_H diff --git a/include/drivers/keyboard.h b/include/drivers/keyboard.h index d445719..68ee284 100644 --- a/include/drivers/keyboard.h +++ b/include/drivers/keyboard.h @@ -10,6 +10,7 @@ #ifndef AVERY_KEYBOARD_H #define AVERY_KEYBOARD_H #include "../core/isr.h" +#include "driver.h" namespace keyboard { extern const unsigned char es[128]; @@ -20,6 +21,8 @@ namespace keyboard { char getChar(); void handler(isr::Registers* regs); void init(); + bool registerDriver(); + bool registerDevice(); } #endif //AVERY_KEYBOARD_H diff --git a/include/drivers/pit.h b/include/drivers/pit.h index e76d091..14dd78b 100644 --- a/include/drivers/pit.h +++ b/include/drivers/pit.h @@ -10,12 +10,15 @@ #ifndef AVERY_PIT_H #define AVERY_PIT_H #include "../core/isr.h" +#include "driver.h" extern "C" void time_handler(isr::Registers* regs); namespace time { u64 getUptime(); void wait(u64 ticksMs); + bool registerDriver(); + bool registerDevice(); } namespace core { diff --git a/include/kernel/memory.h b/include/kernel/memory.h index 0f63461..7563b4f 100644 --- a/include/kernel/memory.h +++ b/include/kernel/memory.h @@ -37,7 +37,7 @@ namespace memory { u64 getUsedMemory(); u64 getFreeMemory(); - struct HeapBlock { + struct alignas(16) HeapBlock { u64 magic; u64 size; bool free; diff --git a/include/types.h b/include/types.h index feb0264..6e5ae05 100644 --- a/include/types.h +++ b/include/types.h @@ -586,4 +586,5 @@ class Vector { } }; + #endif //AVERY_TYPES_H diff --git a/kernel/core/systems.cpp b/kernel/core/systems.cpp index 62b89cc..5785434 100644 --- a/kernel/core/systems.cpp +++ b/kernel/core/systems.cpp @@ -15,8 +15,6 @@ #include "core/idt.h" #include "core/irq.h" #include "core/isr.h" -#include "drivers/keyboard.h" -#include "drivers/pit.h" void core::initSystems() { initGdt(); @@ -33,10 +31,6 @@ void core::initSystems() { initIrq(); debug::log("All IRQs bound correctly"); - initPit(); - debug::log("The Timer is initialized correctly"); - keyboard::init(); - debug::log("The Keyboard is initialized correctly"); asm volatile("sti"); } diff --git a/kernel/drivers/drivers.cpp b/kernel/drivers/drivers.cpp index a4a5d15..6342573 100644 --- a/kernel/drivers/drivers.cpp +++ b/kernel/drivers/drivers.cpp @@ -9,11 +9,25 @@ #include +#include "drivers/keyboard.h" +#include "drivers/pit.h" + +Device* DeviceManager::devices[MaxDevices] = {}; +usize DeviceManager::s_deviceCount = 0; +Driver* DriverManager::drivers[MaxDrivers] = {}; +usize DriverManager::driverCount = 0; + bool DeviceManager::registerDevice(Device* device) { if (!device) { return false; } + for (usize i = 0; i < deviceCount(); i++) { + if (devices[i] == device) { + return true; + } + } + if (deviceCount() >= MaxDevices) { return false; } @@ -30,11 +44,18 @@ bool DriverManager::registerDriver(Driver* driver) { return false; } + for (usize i = 0; i < driverCount; i++) { + if (drivers[i] == driver) { + return true; + } + } + if (driverCount >= MaxDrivers) { return false; } drivers[driverCount++] = driver; + driver->setState(DriverState::Registered); tryBind(*driver); return true; @@ -48,10 +69,18 @@ bool DriverManager::tryBind(Device& device) { for (usize i = 0; i < driverCount; i++) { Driver* driver = drivers[i]; - if (!driver->probe(device)) continue; - if (!driver->start(device)) continue; + driver->setState(DriverState::Probing); + if (!driver->probe(device)) { + driver->setState(DriverState::Registered); + continue; + } + if (!driver->start(device)) { + driver->setState(DriverState::Failed); + continue; + } device.driver = driver; + driver->setState(DriverState::Active); return true; } @@ -64,15 +93,35 @@ bool DriverManager::tryBind(Driver& driver) { if (!device) continue; if (device->driver) continue; - if (!driver.probe(*device)) continue; - if (!driver.start(*device)) continue; + driver.setState(DriverState::Probing); + if (!driver.probe(*device)) { + driver.setState(DriverState::Registered); + continue; + } + if (!driver.start(*device)) { + driver.setState(DriverState::Failed); + continue; + } device->driver = &driver; + driver.setState(DriverState::Active); } return true; } +Device* DeviceManager::deviceAt(usize index) { + if (index >= deviceCount()) { + return nullptr; + } + + return devices[index]; +} + +usize DeviceManager::deviceCount() { + return s_deviceCount; +} + void DeviceManager::unregisterDevice(Device* device) { if (!device) { return; @@ -99,5 +148,40 @@ void DriverManager::unbind(Device& device) { if (!driver) return; driver->stop(device); + driver->setState(DriverState::Registered); device.driver = nullptr; } + +void DriverManager::unregisterDriver(Driver* driver) { + if (!driver) { + return; + } + + for (usize i = 0; i < DeviceManager::deviceCount(); i++) { + Device* device = DeviceManager::deviceAt(i); + + if (device && device->driver == driver) { + unbind(*device); + } + } + + for (usize i = 0; i < driverCount; i++) { + if (drivers[i] == driver) { + for (usize j = i; j + 1 < driverCount; j++) { + drivers[j] = drivers[j + 1]; + } + + drivers[driverCount - 1] = nullptr; + driverCount--; + driver->setState(DriverState::Stopping); + return; + } + } +} + +void drivers::init() { + time::registerDriver(); + time::registerDevice(); + keyboard::registerDriver(); + keyboard::registerDevice(); +} diff --git a/kernel/drivers/input/keyboard.cpp b/kernel/drivers/input/keyboard.cpp index af3f642..dbf497b 100644 --- a/kernel/drivers/input/keyboard.cpp +++ b/kernel/drivers/input/keyboard.cpp @@ -144,6 +144,36 @@ namespace { bool shiftPressed = false; bool extendedScancode = false; + class KeyboardDevice final : public Device { + public: + KeyboardDevice() : Device("ps2-keyboard", DeviceType::Input) { + } + }; + + class KeyboardDriver final : public Driver { + public: + string name() const override { + return "ps2-keyboard"; + } + + bool probe(Device& device) override { + return device.type() == DeviceType::Input; + } + + bool start(Device&) override { + irq::installHandler(1, &keyboard::handler); + return true; + } + + bool stop(Device&) override { + irq::uninstallHandler(1); + return true; + } + }; + + KeyboardDriver* registeredDriver = nullptr; + KeyboardDevice* registeredDevice = nullptr; + void enqueue(char c) { usize nextIndex = (writeIndex + 1) % BufferSize; @@ -209,3 +239,19 @@ char keyboard::getChar() { void keyboard::init() { irq::installHandler(1, &handler); } + +bool keyboard::registerDriver() { + if (!registeredDriver) { + registeredDriver = new KeyboardDriver(); + } + + return DriverManager::registerDriver(registeredDriver); +} + +bool keyboard::registerDevice() { + if (!registeredDevice) { + registeredDevice = new KeyboardDevice(); + } + + return DeviceManager::registerDevice(registeredDevice); +} diff --git a/kernel/drivers/time/pit.cpp b/kernel/drivers/time/pit.cpp index ec7b3d7..c708854 100644 --- a/kernel/drivers/time/pit.cpp +++ b/kernel/drivers/time/pit.cpp @@ -16,17 +16,50 @@ volatile u64 timerTicks; constexpr int TICKS_PER_SECOND = 1000; +namespace { + class PitDevice final : public Device { + public: + PitDevice() : Device("pit", DeviceType::Timer) { + } + }; + + class PitDriver final : public Driver { + public: + string name() const override { + return "pit"; + } + + bool probe(Device& device) override { + return device.type() == DeviceType::Timer; + } + + bool start(Device&) override { + int divisor = 1193180 / TICKS_PER_SECOND; + io::outb(0x43, 0x36); + io::outb(0x40, static_cast(divisor & 0xFF)); + io::outb(0x40, static_cast((divisor >> 8) & 0xFF)); + + irq::installHandler(0, time_handler); + return true; + } + + bool stop(Device&) override { + irq::uninstallHandler(0); + return true; + } + }; + + PitDriver* registeredDriver = nullptr; + PitDevice* registeredDevice = nullptr; +} + extern "C" void time_handler([[maybe_unused]] isr::Registers* regs) { timerTicks = timerTicks + 1; } void core::initPit() { - int divisor = 1193180 / TICKS_PER_SECOND; - io::outb(0x43, 0x36); - io::outb(0x40, divisor & 0xFF); - io::outb(0x40, (divisor >> 8) & 0xFF); - - irq::installHandler(0, time_handler); + time::registerDriver(); + time::registerDevice(); } u64 time::getUptime() { @@ -41,3 +74,18 @@ void time::wait(u64 ms) { } } +bool time::registerDriver() { + if (!registeredDriver) { + registeredDriver = new PitDriver(); + } + + return DriverManager::registerDriver(registeredDriver); +} + +bool time::registerDevice() { + if (!registeredDevice) { + registeredDevice = new PitDevice(); + } + + return DeviceManager::registerDevice(registeredDevice); +} diff --git a/kernel/main.cpp b/kernel/main.cpp index c1dcb1f..2df7f5a 100644 --- a/kernel/main.cpp +++ b/kernel/main.cpp @@ -4,7 +4,7 @@ #include "../include/kernel/console.h" #include "core/regs.h" #include "core/systems.h" -#include "drivers/pit.h" +#include "drivers/driver.h" #include "graphics/framebuffer.h" #include "io/serial.h" #include "kernel/debug.h" @@ -52,6 +52,8 @@ extern "C" [[noreturn]] void _start() { regs::enableSSE(); core::initSystems(); memory::initMemoryServices(memmap_request); + drivers::init(); + debug::log("Drivers initialized"); Framebuffer framebuffer = Framebuffer::createFromLimineRequest(framebuffer_request); out::initFramebufferConsole(framebuffer); diff --git a/kernel/utils/types.cpp b/kernel/utils/types.cpp index 47a5fb0..ff0b3a2 100644 --- a/kernel/utils/types.cpp +++ b/kernel/utils/types.cpp @@ -199,4 +199,10 @@ Option string::operator[](usize index) const { return data[index]; } +extern "C" [[noreturn]] void __cxa_pure_virtual() { + while (true) { + asm volatile("hlt"); + } +} + From 11ee2e335689f1c6a07762aa1005d746d01db32c Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Fri, 5 Jun 2026 13:08:59 +0200 Subject: [PATCH 3/4] Created the MMIO interface support --- include/drivers/driver.h | 38 +++++++++++++++++++ include/kernel/memory/virtualMemory.h | 3 ++ kernel/drivers/mmio.cpp | 53 +++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 kernel/drivers/mmio.cpp diff --git a/include/drivers/driver.h b/include/drivers/driver.h index a132dd2..6726644 100644 --- a/include/drivers/driver.h +++ b/include/drivers/driver.h @@ -140,4 +140,42 @@ namespace drivers { void init(); } +namespace mmio { + static constexpr u64 PageSize = 0x1000; + + class Interface { + public: + Interface(physAddr physical, usize size); + ~Interface(); + + Interface(const Interface&) = delete; + Interface& operator=(const Interface&) = delete; + + template + requires ByteNumber + T read(uptr offset) const { + return *reinterpret_cast( + base + offset + ); + } + + template + requires ByteNumber + void write(uptr offset, T value) { + *reinterpret_cast( + base + offset + ) = value; + } + + uptr address() const { + return base; + } + + private: + uptr base = 0; + virtAddr mappingBase = 0; + usize mappedSize = 0; + }; +} + #endif //AVERY_DRIVER_H diff --git a/include/kernel/memory/virtualMemory.h b/include/kernel/memory/virtualMemory.h index 4ce072f..5bea479 100644 --- a/include/kernel/memory/virtualMemory.h +++ b/include/kernel/memory/virtualMemory.h @@ -24,6 +24,9 @@ namespace vmm { constexpr u64 FlagPresent = 1ull << 0; constexpr u64 FlagWritable = 1ull << 1; constexpr u64 FlagUser = 1ull << 2; + constexpr u64 FlagWriteThrough = 1ull << 3; + constexpr u64 FlagCacheDisable = 1ull << 4; + constexpr u64 FlagGlobal = 1ull << 8; constexpr u64 FlagNX = 1ull << 63; void init(); diff --git a/kernel/drivers/mmio.cpp b/kernel/drivers/mmio.cpp new file mode 100644 index 0000000..b81bba4 --- /dev/null +++ b/kernel/drivers/mmio.cpp @@ -0,0 +1,53 @@ +/* +* mmio.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Memory-Mapped Input & Output functions +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include +#include + +#include "kernel/debug.h" +#include "kernel/memory/virtualMemory.h" + +static virtAddr nextMMIOVirt = 0xFFFF900000000000ull; + +mmio::Interface::Interface(physAddr physical, usize size) { + physAddr alignedPhys = alignDown(physical, static_cast(PageSize)); + u64 offset = physical - alignedPhys; + + mappedSize = alignUp(size + offset, PageSize); + + mappingBase = nextMMIOVirt; + nextMMIOVirt += mappedSize; + + u64 flags = + vmm::FlagPresent | + vmm::FlagWritable | + vmm::FlagCacheDisable | + vmm::FlagGlobal; + + bool ok = vmm::mapRange( + vmm::getKernelPml4(), + mappingBase, + alignedPhys, + mappedSize, + flags + ); + + ASSERT(ok); + + base = mappingBase + offset; +} + +mmio::Interface::~Interface() { + if (!mappingBase || !mappedSize) + return; + + for (u64 off = 0; off < mappedSize; off += PageSize) { + vmm::unmapPage(vmm::getKernelPml4(), mappingBase + off); + } +} From b4712932012a38fcfbf66444da7249d3df21f65f Mon Sep 17 00:00:00 2001 From: Max Van den Eynde Date: Fri, 5 Jun 2026 13:36:30 +0200 Subject: [PATCH 4/4] Moved to APIC and Limine 6 --- README.md | 4 +- include/core/apic.h | 43 ++++++----- include/core/irq.h | 5 +- include/core/pic.h | 23 ++++++ include/core/systems.h | 5 +- include/drivers/driver.h | 12 ++++ include/types.h | 2 +- kernel/core/interrupts/apic/controller.cpp | 84 ++++++++++++++++++++++ kernel/core/interrupts/apic/ioapic.cpp | 75 +++++++++++++++++++ kernel/core/interrupts/apic/lapic.cpp | 52 ++++++++++++++ kernel/core/interrupts/irqs/irq.cpp | 43 ++++++----- kernel/core/interrupts/pic.cpp | 78 ++++++++++++++++++++ kernel/core/interrupts/pic/lapic.cpp | 36 ---------- kernel/core/memory/vmm.cpp | 6 +- kernel/core/systems.cpp | 9 +-- kernel/drivers/mmio.cpp | 8 ++- kernel/main.cpp | 5 +- 17 files changed, 400 insertions(+), 90 deletions(-) create mode 100644 include/core/pic.h create mode 100644 kernel/core/interrupts/apic/controller.cpp create mode 100644 kernel/core/interrupts/apic/ioapic.cpp create mode 100644 kernel/core/interrupts/apic/lapic.cpp create mode 100644 kernel/core/interrupts/pic.cpp delete mode 100644 kernel/core/interrupts/pic/lapic.cpp diff --git a/README.md b/README.md index 57c2900..4efa625 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,9 @@ practices while remaining approachable to contributors and learners alike. - [x] Device objects - [x] Driver registration - [x] Driver lifecycle -- [ ] MMIO port I/O helpers +- [x] MMIO port I/O helpers - [x] Block device abstraction -- [ ] Move to Limine 6 barely (APIC or x2APIC mapped to legacy PIC) +- [x] Move to Limine 6 barely (APIC or x2APIC mapped to legacy PIC) ### Hardware discovery diff --git a/include/core/apic.h b/include/core/apic.h index ef81ac7..4d7200c 100644 --- a/include/core/apic.h +++ b/include/core/apic.h @@ -12,28 +12,37 @@ #include "../types.h" namespace lapic { - inline u64 rdmsr(u32 msr) { - u32 lo, hi; - asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr)); - return (static_cast(hi) << 32) | lo; - } + bool init(); + void eoi(); - inline void wrmsr(u32 msr, u64 value) { - u32 lo = value & 0xffffffff; - u32 hi = value >> 32; + u32 id(); +} + +namespace ioapic { + bool init(physAddr physicalBase); + + u32 read(u8 reg); + void write(u8 reg, u32 value); + + void redirectIRQ(u8 irq, u8 vector, u8 lapicId); + void maskIRQ(u8 irq); + void unmaskIRQ(u8 irq); +} - asm volatile("wrmsr" : : "c"(msr), "a"(lo), "d"(hi)); - } +namespace interruptController { + enum class Backend { + PIC, + APIC + }; - void initBase(); - void write(u32 reg, u32 value); - u32 read(u32 reg); + void initPIC(); + void initAPICCompat(); - constexpr u32 LAPIC_SRV = 0xF0; - void enable(); + void enableIRQ(u8 irq); + void disableIRQ(u8 irq); + void eoi(u8 irq); - constexpr u32 LAPIC_LVT_LINT0 = 0x350; - void enableLegacyMode(); + Backend currentBackend(); } #endif //AVERY_APIC_H diff --git a/include/core/irq.h b/include/core/irq.h index a9fdf3a..027921a 100644 --- a/include/core/irq.h +++ b/include/core/irq.h @@ -35,7 +35,10 @@ namespace irq { void installHandler(int irq, IRQHandler); void uninstallHandler(int irq); - void remap(); + + void enable(int irq); + void disable(int irq); + void eoi(int irq); } namespace core { diff --git a/include/core/pic.h b/include/core/pic.h new file mode 100644 index 0000000..3020e28 --- /dev/null +++ b/include/core/pic.h @@ -0,0 +1,23 @@ +/* +* pic.h +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Handler for the legacy PIC +* Copyright (c) 2026 Max Van den Eynde +*/ + +#ifndef AVERY_PIC_H +#define AVERY_PIC_H +#include "../types.h" + +namespace pic { + void remap(); + void maskAll(); + + void enableIRQ(u8 irq); + void disableIRQ(u8 irq); + void eoi(u8 irq); +} + +#endif //AVERY_PIC_H diff --git a/include/core/systems.h b/include/core/systems.h index f38e687..f81df47 100644 --- a/include/core/systems.h +++ b/include/core/systems.h @@ -10,8 +10,11 @@ #ifndef AVERY_SYSTEMS_H #define AVERY_SYSTEMS_H +struct limine_memmap_request; + + namespace core { - void initSystems(); + void initSystems(volatile struct limine_memmap_request& request); } #endif //AVERY_SYSTEMS_H diff --git a/include/drivers/driver.h b/include/drivers/driver.h index 6726644..4970689 100644 --- a/include/drivers/driver.h +++ b/include/drivers/driver.h @@ -154,6 +154,10 @@ namespace mmio { template requires ByteNumber T read(uptr offset) const { + if (!base) { + return T{}; + } + return *reinterpret_cast( base + offset ); @@ -162,6 +166,10 @@ namespace mmio { template requires ByteNumber void write(uptr offset, T value) { + if (!base) { + return; + } + *reinterpret_cast( base + offset ) = value; @@ -171,6 +179,10 @@ namespace mmio { return base; } + bool isValid() const { + return base != 0; + } + private: uptr base = 0; virtAddr mappingBase = 0; diff --git a/include/types.h b/include/types.h index 6e5ae05..74aeb2b 100644 --- a/include/types.h +++ b/include/types.h @@ -68,7 +68,7 @@ T alignUp(T x, T a) { template requires ByteNumber T alignDown(T x, T a) { - return (x + a - 1) & ~(a - 1); + return x & ~(a - 1); } template diff --git a/kernel/core/interrupts/apic/controller.cpp b/kernel/core/interrupts/apic/controller.cpp new file mode 100644 index 0000000..240d875 --- /dev/null +++ b/kernel/core/interrupts/apic/controller.cpp @@ -0,0 +1,84 @@ +/* +* controller.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Interrupt controller +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +#include "core/pic.h" + +namespace interruptController { + static Backend backend = Backend::PIC; + + constexpr u8 IRQ_BASE = 0x20; + + constexpr physAddr IOAPIC_PHYS = 0xFEC00000; + + static u8 irqToVector(u8 irq) { + return IRQ_BASE + irq; + } + + void initPIC() { + backend = Backend::PIC; + + pic::remap(); + } + + void initAPICCompat() { + if (!ioapic::init(IOAPIC_PHYS)) { + initPIC(); + return; + } + + if (!lapic::init()) { + initPIC(); + return; + } + + backend = Backend::APIC; + + pic::maskAll(); + + u8 lapicId = static_cast(lapic::id()); + + for (u8 irq = 0; irq < 16; irq++) { + ioapic::redirectIRQ(irq, irqToVector(irq), lapicId); + ioapic::maskIRQ(irq); + } + } + + void enableIRQ(u8 irq) { + if (backend == Backend::PIC) { + pic::enableIRQ(irq); + } + else { + ioapic::unmaskIRQ(irq); + } + } + + void disableIRQ(u8 irq) { + if (backend == Backend::PIC) { + pic::disableIRQ(irq); + } + else { + ioapic::maskIRQ(irq); + } + } + + void eoi(u8 irq) { + if (backend == Backend::PIC) { + pic::eoi(irq); + } + else { + lapic::eoi(); + } + } + + Backend currentBackend() { + return backend; + } +} diff --git a/kernel/core/interrupts/apic/ioapic.cpp b/kernel/core/interrupts/apic/ioapic.cpp new file mode 100644 index 0000000..6127de7 --- /dev/null +++ b/kernel/core/interrupts/apic/ioapic.cpp @@ -0,0 +1,75 @@ +/* +* ioapic.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Input / Output Advanced Programmable Interrupt Controller +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +#include "drivers/driver.h" + +namespace ioapic { + static mmio::Interface* interface = nullptr; + constexpr u32 IOAPIC_REGSEL = 0x00; + constexpr u32 IOAPIC_WINDOW = 0x10; + + constexpr u8 IOAPIC_REDTBL = 0x10; + + bool init(physAddr physicalBase) { + interface = new mmio::Interface(physicalBase, 0x1000); + return interface->isValid(); + } + + u32 read(u8 reg) { + interface->write(IOAPIC_REGSEL, reg); + return interface->read(IOAPIC_WINDOW); + } + + void write(u8 reg, u32 value) { + interface->write(IOAPIC_REGSEL, reg); + interface->write(IOAPIC_WINDOW, value); + } + + void redirectIRQ(u8 irq, u8 vector, u8 lapicId) { + u8 lowReg = IOAPIC_REDTBL + irq * 2; + u8 highReg = lowReg + 1; + + u32 low = vector; + + low |= 0 << 8; + + low |= 0 << 11; + + low |= 0 << 13; + + low |= 0 << 15; + + low &= ~(1u << 16); + + u32 high = static_cast(lapicId) << 24; + + write(highReg, high); + write(lowReg, low); + } + + void maskIRQ(u8 irq) { + u8 lowReg = IOAPIC_REDTBL + irq * 2; + + u32 low = read(lowReg); + low |= 1u << 16; + + write(lowReg, low); + } + + void unmaskIRQ(u8 irq) { + u8 lowReg = IOAPIC_REDTBL + irq * 2; + + u32 low = read(lowReg); + low &= ~(1u << 16); + + write(lowReg, low); + } +} diff --git a/kernel/core/interrupts/apic/lapic.cpp b/kernel/core/interrupts/apic/lapic.cpp new file mode 100644 index 0000000..9e11870 --- /dev/null +++ b/kernel/core/interrupts/apic/lapic.cpp @@ -0,0 +1,52 @@ +/* +* lapic.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Local Advanced Programmable Interrupt Controller definitions +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +#include "drivers/driver.h" + +namespace lapic { + static mmio::Interface* interface = nullptr; + + constexpr physAddr LAPIC_PHYS = 0xFEE00000; + + constexpr u32 LAPIC_ID = 0x020; + constexpr u32 LAPIC_EOI = 0x0B0; + constexpr u32 LAPIC_SVR = 0x0F0; + + static u32 read(u32 offset) { + return interface->read(offset); + } + + static void write(u32 offset, u32 value) { + interface->write(offset, value); + } + + bool init() { + interface = new mmio::Interface(LAPIC_PHYS, 0x1000); + + if (!interface->isValid()) { + return false; + } + + u32 svr = read(LAPIC_SVR); + + write(LAPIC_SVR, svr | 0x100 | 0xFF); + + return true; + } + + void eoi() { + write(LAPIC_EOI, 0); + } + + u32 id() { + return read(LAPIC_ID) >> 24; + } +} diff --git a/kernel/core/interrupts/irqs/irq.cpp b/kernel/core/interrupts/irqs/irq.cpp index 83bd939..5012eef 100644 --- a/kernel/core/interrupts/irqs/irq.cpp +++ b/kernel/core/interrupts/irqs/irq.cpp @@ -9,6 +9,7 @@ #include "core/irq.h" +#include "core/apic.h" #include "core/idt.h" #include "io/io.h" @@ -19,28 +20,27 @@ irq::IRQHandler irq_routines[16] = { void irq::installHandler(int irq, IRQHandler handler) { irq_routines[irq] = handler; + enable(irq); } void irq::uninstallHandler(int irq) { + disable(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 irq::enable(int irq) { + interruptController::enableIRQ(static_cast(irq)); } -void core::initIrq() { - irq::remap(); +void irq::disable(int irq) { + interruptController::disableIRQ(static_cast(irq)); +} + +void irq::eoi(int irq) { + interruptController::eoi(static_cast(irq)); +} +void core::initIrq() { 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); @@ -57,16 +57,21 @@ void core::initIrq() { 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); + + interruptController::initAPICCompat(); } extern "C" void irq_handler(isr::Registers* regs) { - if (irq::IRQHandler handler = irq_routines[regs->int_no - 32]) { - handler(regs); - } + u64 vector = regs->int_no; + + if (vector < 32 || vector > 47) + return; - if (regs->int_no >= 40) { - io::outb(0xA0, 0x20); + u8 irqNumber = static_cast(vector - 32); + + if (irq::IRQHandler handler = irq_routines[irqNumber]) { + handler(regs); } - io::outb(0x20, 0x20); + irq::eoi(irqNumber); } diff --git a/kernel/core/interrupts/pic.cpp b/kernel/core/interrupts/pic.cpp new file mode 100644 index 0000000..23bb461 --- /dev/null +++ b/kernel/core/interrupts/pic.cpp @@ -0,0 +1,78 @@ +/* +* pic.cpp +* As part of the Avery project +* Created by Max Van den Eynde in 2026 +* -------------------------------------- +* Description: Functions for the PIC +* Copyright (c) 2026 Max Van den Eynde +*/ + +#include + +#include "io/io.h" + +namespace pic { + constexpr u16 PIC1_COMMAND = 0x20; + constexpr u16 PIC1_DATA = 0x21; + constexpr u16 PIC2_COMMAND = 0xA0; + constexpr u16 PIC2_DATA = 0xA1; + + void remap() { + io::outb(PIC1_COMMAND, 0x11); + io::outb(PIC2_COMMAND, 0x11); + + io::outb(PIC1_DATA, 0x20); + io::outb(PIC2_DATA, 0x28); + + io::outb(PIC1_DATA, 0x04); + io::outb(PIC2_DATA, 0x02); + + io::outb(PIC1_DATA, 0x01); + io::outb(PIC2_DATA, 0x01); + + io::outb(PIC1_DATA, 0x00); + io::outb(PIC2_DATA, 0x00); + } + + void maskAll() { + io::outb(PIC1_DATA, 0xFF); + io::outb(PIC2_DATA, 0xFF); + } + + void enableIRQ(u8 irq) { + u16 port; + + if (irq < 8) { + port = PIC1_DATA; + } + else { + port = PIC2_DATA; + irq -= 8; + } + + u8 value = io::inb(port) & ~(1 << irq); + io::outb(port, value); + } + + void disableIRQ(u8 irq) { + u16 port; + + if (irq < 8) { + port = PIC1_DATA; + } + else { + port = PIC2_DATA; + irq -= 8; + } + + u8 value = io::inb(port) | static_cast(1 << irq); + io::outb(port, value); + } + + void eoi(u8 irq) { + if (irq >= 8) { + io::outb(PIC2_COMMAND, 0x20); + } + io::outb(PIC1_COMMAND, 0x20); + } +} diff --git a/kernel/core/interrupts/pic/lapic.cpp b/kernel/core/interrupts/pic/lapic.cpp deleted file mode 100644 index 26e1943..0000000 --- a/kernel/core/interrupts/pic/lapic.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -* lapic.cpp -* As part of the Avery project -* Created by Max Van den Eynde in 2026 -* -------------------------------------- -* Description: Local Advanced Programmable Interrupt Controler interfaces -* Copyright (c) 2026 Max Van den Eynde -*/ - -#include "core/apic.h" -#include "kernel/memory.h" - -static volatile u32* LapicBase = nullptr; - -void lapic::initBase() { - u64 apicBaseMsr = rdmsr(0x1B); - uptr phys = apicBaseMsr & 0xFFFFF000; - u64 hhdm = memory::getHHDMOffset(); - LapicBase = reinterpret_cast(hhdm + phys); -} - -void lapic::write(u32 reg, u32 value) { - *reinterpret_cast(reinterpret_cast(LapicBase) + reg) = value; -} - -u32 lapic::read(u32 reg) { - return *reinterpret_cast(reinterpret_cast(LapicBase) + reg); -} - -void lapic::enable() { - write(LAPIC_SRV, read(LAPIC_SRV) | 0x100 | 0xFF); -} - -void lapic::enableLegacyMode() { - write(LAPIC_LVT_LINT0, 0x700); -} diff --git a/kernel/core/memory/vmm.cpp b/kernel/core/memory/vmm.cpp index eeddee9..e4866f5 100644 --- a/kernel/core/memory/vmm.cpp +++ b/kernel/core/memory/vmm.cpp @@ -72,13 +72,13 @@ u64* vmm::getPte(PageTable* pml4, virtAddr virt, bool create) { return nullptr; } - PageTable* pt = getNextTable(pd, PT_INDEX(virt), create); + PageTable* pt = getNextTable(pd, PD_INDEX(virt), create); if (!pt) { return nullptr; } - return &pt->entries[PDPT_INDEX(virt)]; + return &pt->entries[PT_INDEX(virt)]; } bool vmm::mapPage(PageTable* pml4, virtAddr virt, physAddr phys, u64 flags) { @@ -98,6 +98,8 @@ bool vmm::mapPage(PageTable* pml4, virtAddr virt, physAddr phys, u64 flags) { *pte = (phys & PTE_ADDR_MASK) | flags | PTE_PRESENT; + asm volatile("invlpg (%0)" :: "r"(virt) : "memory"); + return true; } diff --git a/kernel/core/systems.cpp b/kernel/core/systems.cpp index 5785434..545af4b 100644 --- a/kernel/core/systems.cpp +++ b/kernel/core/systems.cpp @@ -11,12 +11,12 @@ #include "kernel/debug.h" #include -#include "core/apic.h" #include "core/idt.h" #include "core/irq.h" #include "core/isr.h" +#include "kernel/memory.h" -void core::initSystems() { +void core::initSystems(volatile struct limine_memmap_request& request) { initGdt(); debug::log("Initialized GDT"); initIdt(); @@ -24,10 +24,7 @@ void core::initSystems() { initIsrs(); debug::log("All ISRs bound correctly"); - //lapic::initBase(); - //lapic::enable(); - //lapic::enableLegacyMode(); - debug::log("Using PIC Legacy Mode"); + memory::initMemoryServices(request); initIrq(); debug::log("All IRQs bound correctly"); diff --git a/kernel/drivers/mmio.cpp b/kernel/drivers/mmio.cpp index b81bba4..53c5ab3 100644 --- a/kernel/drivers/mmio.cpp +++ b/kernel/drivers/mmio.cpp @@ -10,7 +10,6 @@ #include #include -#include "kernel/debug.h" #include "kernel/memory/virtualMemory.h" static virtAddr nextMMIOVirt = 0xFFFF900000000000ull; @@ -38,7 +37,12 @@ mmio::Interface::Interface(physAddr physical, usize size) { flags ); - ASSERT(ok); + if (!ok) { + mappingBase = 0; + mappedSize = 0; + base = 0; + return; + } base = mappingBase + offset; } diff --git a/kernel/main.cpp b/kernel/main.cpp index 2df7f5a..8c9dd42 100644 --- a/kernel/main.cpp +++ b/kernel/main.cpp @@ -11,7 +11,7 @@ #include "kernel/memory.h" __attribute__((used, section(".limine_requests"))) -static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(4); +static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(6); __attribute__((used, section(".limine_requests"))) static volatile struct limine_framebuffer_request framebuffer_request = { @@ -50,8 +50,7 @@ extern "C" [[noreturn]] void _start() { memory::setHHDM(hddm_request); regs::enableSSE(); - core::initSystems(); - memory::initMemoryServices(memmap_request); + core::initSystems(memmap_request); drivers::init(); debug::log("Drivers initialized");