feat: Local/IO APIC, PS/2 keyboard & mouse

This commit is contained in:
2026-02-17 12:44:31 +01:00
parent e2f059bf90
commit 641ec4681b
26 changed files with 1730 additions and 3 deletions
+75
View File
@@ -0,0 +1,75 @@
/*
* Apic.cpp
* Local APIC (Advanced Programmable Interrupt Controller)
* Copyright (c) 2025 Daniel Hammer
*/
#include "Apic.hpp"
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include <Memory/HHDM.hpp>
using namespace Kt;
namespace Hal {
namespace LocalApic {
static volatile uint32_t* g_apicBase = nullptr;
static inline uint64_t ReadMSR(uint32_t msr) {
uint32_t lo, hi;
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return ((uint64_t)hi << 32) | lo;
}
static inline void WriteMSR(uint32_t msr, uint64_t value) {
uint32_t lo = (uint32_t)(value & 0xFFFFFFFF);
uint32_t hi = (uint32_t)(value >> 32);
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
}
uint32_t ReadRegister(uint32_t reg) {
return g_apicBase[reg / 4];
}
void WriteRegister(uint32_t reg, uint32_t value) {
g_apicBase[reg / 4] = value;
}
void Initialize(uint64_t apicBasePhys) {
// Read the APIC base MSR to verify/confirm the base address
uint64_t msrValue = ReadMSR(MSR_APIC_BASE);
uint64_t msrBase = msrValue & 0xFFFFF000;
KernelLogStream(DEBUG, "APIC") << "MSR APIC base: " << base::hex << msrBase;
KernelLogStream(DEBUG, "APIC") << "MADT APIC base: " << base::hex << apicBasePhys;
// Use the MADT-provided address (it should match MSR)
g_apicBase = (volatile uint32_t*)Memory::HHDM(apicBasePhys);
// Enable the APIC by setting bit 8 (APIC Software Enable) in SVR
// and set the spurious interrupt vector
uint32_t svr = ReadRegister(REG_SPURIOUS);
svr |= (1 << 8); // Enable APIC
svr = (svr & 0xFFFFFF00) | SPURIOUS_VECTOR; // Set spurious vector
WriteRegister(REG_SPURIOUS, svr);
// Set Task Priority to 0 to accept all interrupts
WriteRegister(REG_TPR, 0);
uint32_t version = ReadRegister(REG_VERSION);
uint32_t id = GetId();
KernelLogStream(OK, "APIC") << "Local APIC initialized: id=" << base::dec << (uint64_t)id
<< " version=" << base::hex << (uint64_t)(version & 0xFF)
<< " max LVT=" << base::dec << (uint64_t)((version >> 16) & 0xFF);
}
void SendEOI() {
WriteRegister(REG_EOI, 0);
}
uint32_t GetId() {
return (ReadRegister(REG_ID) >> 24) & 0xFF;
}
};
};
+41
View File
@@ -0,0 +1,41 @@
/*
* Apic.hpp
* Local APIC (Advanced Programmable Interrupt Controller)
* Copyright (c) 2025 Daniel Hammer
*/
#pragma once
#include <cstdint>
namespace Hal {
namespace LocalApic {
// Local APIC register offsets
constexpr uint32_t REG_ID = 0x020;
constexpr uint32_t REG_VERSION = 0x030;
constexpr uint32_t REG_TPR = 0x080;
constexpr uint32_t REG_EOI = 0x0B0;
constexpr uint32_t REG_SPURIOUS = 0x0F0;
constexpr uint32_t REG_ICR_LOW = 0x300;
constexpr uint32_t REG_ICR_HIGH = 0x310;
constexpr uint32_t REG_TIMER_LVT = 0x320;
constexpr uint32_t REG_LINT0_LVT = 0x350;
constexpr uint32_t REG_LINT1_LVT = 0x360;
constexpr uint32_t REG_ERROR_LVT = 0x370;
constexpr uint32_t REG_TIMER_INITIAL = 0x380;
constexpr uint32_t REG_TIMER_CURRENT = 0x390;
constexpr uint32_t REG_TIMER_DIVIDE = 0x3E0;
// Spurious vector number
constexpr uint8_t SPURIOUS_VECTOR = 0xFF;
// MSR for APIC base
constexpr uint32_t MSR_APIC_BASE = 0x1B;
void Initialize(uint64_t apicBasePhys);
void SendEOI();
uint32_t GetId();
uint32_t ReadRegister(uint32_t reg);
void WriteRegister(uint32_t reg, uint32_t value);
};
};
+72
View File
@@ -0,0 +1,72 @@
/*
* ApicInit.cpp
* APIC subsystem initialization
* Copyright (c) 2025 Daniel Hammer
*/
#include "ApicInit.hpp"
#include "Pic.hpp"
#include "Apic.hpp"
#include "IoApic.hpp"
#include "Interrupts.hpp"
#include <ACPI/MADT.hpp>
#include <Hal/IDT.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include <Memory/Paging.hpp>
#include <Memory/HHDM.hpp>
using namespace Kt;
namespace Hal {
void ApicInitialize(ACPI::CommonSDTHeader* xsdt) {
KernelLogStream(INFO, "APIC") << "Initializing APIC subsystem";
// Step 1: Parse MADT
MADT::ParsedMADT madt{};
if (!MADT::Parse(xsdt, madt)) {
KernelLogStream(ERROR, "APIC") << "Failed to parse MADT, cannot initialize APIC";
return;
}
if (madt.IoApicAddress == 0) {
KernelLogStream(ERROR, "APIC") << "No IOAPIC found in MADT";
return;
}
// Step 2: Map APIC MMIO regions into kernel page tables
// The HHDM only covers physical RAM; MMIO regions need explicit mapping.
if (Memory::VMM::g_paging) {
Memory::VMM::g_paging->MapMMIO(madt.LocalApicAddress, Memory::HHDM(madt.LocalApicAddress));
KernelLogStream(DEBUG, "APIC") << "Mapped Local APIC MMIO at phys " << base::hex << madt.LocalApicAddress;
Memory::VMM::g_paging->MapMMIO(madt.IoApicAddress, Memory::HHDM(madt.IoApicAddress));
KernelLogStream(DEBUG, "APIC") << "Mapped IOAPIC MMIO at phys " << base::hex << madt.IoApicAddress;
}
// Step 3: Disable legacy 8259 PIC
DisableLegacyPic();
// Step 4: Install IRQ stubs into IDT
InitializeIrqHandlers();
IDTReload();
// Step 5: Initialize Local APIC
LocalApic::Initialize(madt.LocalApicAddress);
// Step 6: Initialize IOAPIC
IoApic::Initialize(madt.IoApicAddress, madt.IoApicGsiBase,
madt.Overrides, madt.OverrideCount);
// Step 7: Route keyboard (IRQ1) and mouse (IRQ12) to BSP
uint8_t bspApicId = (uint8_t)LocalApic::GetId();
IoApic::RouteIrq(IRQ_KEYBOARD, IRQ_VECTOR_BASE + IRQ_KEYBOARD, bspApicId);
IoApic::RouteIrq(IRQ_MOUSE, IRQ_VECTOR_BASE + IRQ_MOUSE, bspApicId);
// Step 8: Enable interrupts
asm volatile("sti");
KernelLogStream(OK, "APIC") << "APIC subsystem initialized, interrupts enabled";
}
};
+22
View File
@@ -0,0 +1,22 @@
/*
* ApicInit.hpp
* APIC subsystem initialization
* Copyright (c) 2025 Daniel Hammer
*/
#pragma once
#include <ACPI/ACPI.hpp>
namespace Hal {
// Initialize the full APIC subsystem:
// 1. Parse MADT from XSDT
// 2. Disable legacy PIC
// 3. Install IRQ stubs in IDT
// 4. Initialize Local APIC
// 5. Initialize IOAPIC
// 6. Route keyboard (IRQ1) and mouse (IRQ12)
// 7. Enable interrupts
//
// xsdt: pointer to the XSDT (already HHDM-mapped)
void ApicInitialize(ACPI::CommonSDTHeader* xsdt);
};
+51
View File
@@ -0,0 +1,51 @@
/*
* Interrupts.cpp
* Hardware interrupt registration and dispatch
* Copyright (c) 2025 Daniel Hammer
*/
#include "Interrupts.hpp"
#include "Apic.hpp"
#include <Hal/IDT.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
// Assembly-defined stub table and spurious handler
extern "C" void* IrqStubTable[Hal::IRQ_COUNT];
extern "C" void IrqStubSpurious();
namespace Hal {
// Dispatch table: one handler per IRQ
static IrqHandler g_irqHandlers[IRQ_COUNT] = {};
void RegisterIrqHandler(uint8_t irq, IrqHandler handler) {
if (irq >= IRQ_COUNT) return;
g_irqHandlers[irq] = handler;
Kt::KernelLogStream(Kt::DEBUG, "IRQ") << "Registered handler for IRQ " << base::dec << (uint64_t)irq
<< " (vector " << (uint64_t)(IRQ_VECTOR_BASE + irq) << ")";
}
void InitializeIrqHandlers() {
// Install IRQ stubs into IDT vectors 32..55
for (int i = 0; i < IRQ_COUNT; i++) {
IDTEncodeInterrupt(IRQ_VECTOR_BASE + i, IrqStubTable[i], 0x8E);
}
// Install spurious interrupt handler at vector 0xFF
IDTEncodeInterrupt(0xFF, (void*)IrqStubSpurious, 0x8E);
Kt::KernelLogStream(Kt::OK, "IRQ") << "Installed " << base::dec << (uint64_t)IRQ_COUNT
<< " IRQ stubs (vectors " << (uint64_t)IRQ_VECTOR_BASE << "-"
<< (uint64_t)(IRQ_VECTOR_BASE + IRQ_COUNT - 1) << ")";
}
};
// C linkage dispatch function called from assembly stubs
extern "C" void HalIrqDispatch(uint64_t irqNumber) {
if (irqNumber < Hal::IRQ_COUNT && Hal::g_irqHandlers[irqNumber] != nullptr) {
Hal::g_irqHandlers[irqNumber]((uint8_t)irqNumber);
}
// Send End of Interrupt to the Local APIC
Hal::LocalApic::SendEOI();
}
+37
View File
@@ -0,0 +1,37 @@
/*
* Interrupts.hpp
* Hardware interrupt registration and dispatch
* Copyright (c) 2025 Daniel Hammer
*/
#pragma once
#include <cstdint>
namespace Hal {
// IRQ handler function type. The parameter is the IRQ number (0-23).
using IrqHandler = void(*)(uint8_t irq);
// Number of IRQ lines supported (IOAPIC inputs)
constexpr int IRQ_COUNT = 24;
// IRQ vector base: hardware IRQs start at IDT vector 32
constexpr uint8_t IRQ_VECTOR_BASE = 32;
// Well-known ISA IRQ assignments
constexpr uint8_t IRQ_TIMER = 0;
constexpr uint8_t IRQ_KEYBOARD = 1;
constexpr uint8_t IRQ_CASCADE = 2;
constexpr uint8_t IRQ_COM2 = 3;
constexpr uint8_t IRQ_COM1 = 4;
constexpr uint8_t IRQ_FLOPPY = 6;
constexpr uint8_t IRQ_RTC = 8;
constexpr uint8_t IRQ_MOUSE = 12;
constexpr uint8_t IRQ_ATA1 = 14;
constexpr uint8_t IRQ_ATA2 = 15;
// Register a handler for the given IRQ number (0-23)
void RegisterIrqHandler(uint8_t irq, IrqHandler handler);
// Install IRQ stubs into the IDT and set up the dispatch table
void InitializeIrqHandlers();
};
+137
View File
@@ -0,0 +1,137 @@
/*
* IoApic.cpp
* I/O APIC (I/O Advanced Programmable Interrupt Controller)
* Copyright (c) 2025 Daniel Hammer
*/
#include "IoApic.hpp"
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
#include <Memory/HHDM.hpp>
using namespace Kt;
namespace Hal {
namespace IoApic {
static volatile uint32_t* g_ioApicBase = nullptr;
static uint32_t g_gsiBase = 0;
static uint32_t g_maxRedirEntries = 0;
// Stored overrides for IRQ remapping
static MADT::InterruptSourceOverride g_overrides[MADT::ParsedMADT::MaxOverrides];
static int g_overrideCount = 0;
static uint32_t ReadRegister(uint32_t reg) {
// Write the register index to IOREGSEL (offset 0x00)
g_ioApicBase[0] = reg;
// Read the value from IOWIN (offset 0x10 = index 4 in uint32_t array)
return g_ioApicBase[4];
}
static void WriteRegister(uint32_t reg, uint32_t value) {
g_ioApicBase[0] = reg;
g_ioApicBase[4] = value;
}
void SetRedirectionEntry(uint8_t index, uint64_t entry) {
uint32_t regLow = IOREDTBL_BASE + (index * 2);
uint32_t regHigh = IOREDTBL_BASE + (index * 2) + 1;
WriteRegister(regHigh, (uint32_t)(entry >> 32));
WriteRegister(regLow, (uint32_t)(entry & 0xFFFFFFFF));
}
uint64_t GetRedirectionEntry(uint8_t index) {
uint32_t regLow = IOREDTBL_BASE + (index * 2);
uint32_t regHigh = IOREDTBL_BASE + (index * 2) + 1;
uint64_t low = ReadRegister(regLow);
uint64_t high = ReadRegister(regHigh);
return (high << 32) | low;
}
void MaskIrq(uint8_t irq) {
uint64_t entry = GetRedirectionEntry(irq);
entry |= REDIR_MASKED;
SetRedirectionEntry(irq, entry);
}
void UnmaskIrq(uint8_t irq) {
uint64_t entry = GetRedirectionEntry(irq);
entry &= ~REDIR_MASKED;
SetRedirectionEntry(irq, entry);
}
uint32_t GetGsiForIrq(uint8_t isaIrq) {
for (int i = 0; i < g_overrideCount; i++) {
if (g_overrides[i].IrqSource == isaIrq) {
return g_overrides[i].GlobalSystemInterrupt;
}
}
// No override found, identity map
return isaIrq;
}
void RouteIrq(uint8_t isaIrq, uint8_t vector, uint8_t destinationApicId) {
uint32_t gsi = GetGsiForIrq(isaIrq);
uint32_t ioApicIndex = gsi - g_gsiBase;
// Build redirection entry
uint64_t entry = 0;
entry |= vector; // Vector
entry |= ((uint64_t)destinationApicId << 56); // Destination
// Check if there's an override with specific polarity/trigger settings
for (int i = 0; i < g_overrideCount; i++) {
if (g_overrides[i].IrqSource == isaIrq) {
uint16_t flags = g_overrides[i].Flags;
// Polarity: bits 0-1 (0b11 = active low)
if ((flags & 0x03) == 0x03) {
entry |= REDIR_ACTIVE_LOW;
}
// Trigger mode: bits 2-3 (0b11 = level triggered)
if ((flags & 0x0C) == 0x0C) {
entry |= REDIR_LEVEL_TRIGGER;
}
break;
}
}
SetRedirectionEntry(ioApicIndex, entry);
KernelLogStream(DEBUG, "IOAPIC") << "Routed ISA IRQ " << base::dec << (uint64_t)isaIrq
<< " -> GSI " << (uint64_t)gsi
<< " -> vector " << (uint64_t)vector
<< " -> APIC " << (uint64_t)destinationApicId;
}
void Initialize(uint64_t ioApicBasePhys, uint32_t gsiBase,
MADT::InterruptSourceOverride* overrides, int overrideCount) {
g_ioApicBase = (volatile uint32_t*)Memory::HHDM(ioApicBasePhys);
g_gsiBase = gsiBase;
// Store overrides
g_overrideCount = overrideCount;
for (int i = 0; i < overrideCount; i++) {
g_overrides[i] = overrides[i];
}
// Read IOAPIC version and max redirection entries
uint32_t version = ReadRegister(IOAPICVER);
g_maxRedirEntries = ((version >> 16) & 0xFF) + 1;
uint32_t ioapicId = (ReadRegister(IOAPICID) >> 24) & 0x0F;
KernelLogStream(OK, "IOAPIC") << "IOAPIC initialized: id=" << base::dec << (uint64_t)ioapicId
<< " version=" << base::hex << (uint64_t)(version & 0xFF)
<< " entries=" << base::dec << (uint64_t)g_maxRedirEntries;
// Mask all redirection entries initially
for (uint32_t i = 0; i < g_maxRedirEntries; i++) {
SetRedirectionEntry(i, REDIR_MASKED | (IRQ_VECTOR_BASE + i));
}
KernelLogStream(OK, "IOAPIC") << "All redirection entries masked";
}
};
};
+44
View File
@@ -0,0 +1,44 @@
/*
* IoApic.hpp
* I/O APIC (I/O Advanced Programmable Interrupt Controller)
* Copyright (c) 2025 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include <ACPI/MADT.hpp>
namespace Hal {
namespace IoApic {
// IOAPIC register indices (written to IOREGSEL)
constexpr uint32_t IOAPICID = 0x00;
constexpr uint32_t IOAPICVER = 0x01;
constexpr uint32_t IOAPICARB = 0x02;
// Redirection table entries start at 0x10, each entry is 2 x 32-bit registers
constexpr uint32_t IOREDTBL_BASE = 0x10;
// Redirection entry flags
constexpr uint64_t REDIR_MASKED = (1ULL << 16);
constexpr uint64_t REDIR_LEVEL_TRIGGER = (1ULL << 15);
constexpr uint64_t REDIR_ACTIVE_LOW = (1ULL << 13);
constexpr uint64_t REDIR_LOGICAL_DEST = (1ULL << 11);
// IRQ vector base: hardware IRQs start at vector 32
constexpr uint8_t IRQ_VECTOR_BASE = 32;
void Initialize(uint64_t ioApicBasePhys, uint32_t gsiBase,
MADT::InterruptSourceOverride* overrides, int overrideCount);
void SetRedirectionEntry(uint8_t irq, uint64_t entry);
uint64_t GetRedirectionEntry(uint8_t irq);
void MaskIrq(uint8_t irq);
void UnmaskIrq(uint8_t irq);
// Route an ISA IRQ to a specific vector, applying source overrides
void RouteIrq(uint8_t isaIrq, uint8_t vector, uint8_t destinationApicId);
// Get the GSI for a given ISA IRQ (applies overrides)
uint32_t GetGsiForIrq(uint8_t isaIrq);
};
};
+127
View File
@@ -0,0 +1,127 @@
;
; IsrStubs.asm
; Hardware interrupt (IRQ) entry stubs for APIC
; Copyright (c) 2025 Daniel Hammer
;
[bits 64]
section .text
; External C++ handler function
extern HalIrqDispatch
; Macro to define an IRQ stub
; Each stub pushes the IRQ number and jumps to the common handler
%macro IRQ_STUB 1
global IrqStub%1
IrqStub%1:
push rax ; Save rax (we use it for the IRQ number)
mov rax, %1 ; IRQ number
jmp IrqCommon
%endmacro
; Common IRQ handler: saves all general-purpose registers,
; calls the C++ dispatch function, restores registers, and returns.
IrqCommon:
; rax is already on the stack and holds the IRQ number
push rcx
push rdx
push rbx
push rbp
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
; Pass IRQ number as first argument (rdi)
mov rdi, rax
; Align stack to 16 bytes before call (we pushed 15 registers x 8 = 120 bytes
; + return address 8 = 128, which is 16-byte aligned, so we're good)
cld
call HalIrqDispatch
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rbp
pop rbx
pop rdx
pop rcx
pop rax
iretq
; Define stubs for IRQs 0..23 (vectors 32..55)
; This covers all standard ISA IRQs plus some extra IOAPIC inputs
IRQ_STUB 0
IRQ_STUB 1
IRQ_STUB 2
IRQ_STUB 3
IRQ_STUB 4
IRQ_STUB 5
IRQ_STUB 6
IRQ_STUB 7
IRQ_STUB 8
IRQ_STUB 9
IRQ_STUB 10
IRQ_STUB 11
IRQ_STUB 12
IRQ_STUB 13
IRQ_STUB 14
IRQ_STUB 15
IRQ_STUB 16
IRQ_STUB 17
IRQ_STUB 18
IRQ_STUB 19
IRQ_STUB 20
IRQ_STUB 21
IRQ_STUB 22
IRQ_STUB 23
; Spurious interrupt handler (vector 0xFF) - do nothing, no EOI
global IrqStubSpurious
IrqStubSpurious:
iretq
; Export the stub table for C++ to reference
section .data
global IrqStubTable
IrqStubTable:
dq IrqStub0
dq IrqStub1
dq IrqStub2
dq IrqStub3
dq IrqStub4
dq IrqStub5
dq IrqStub6
dq IrqStub7
dq IrqStub8
dq IrqStub9
dq IrqStub10
dq IrqStub11
dq IrqStub12
dq IrqStub13
dq IrqStub14
dq IrqStub15
dq IrqStub16
dq IrqStub17
dq IrqStub18
dq IrqStub19
dq IrqStub20
dq IrqStub21
dq IrqStub22
dq IrqStub23
+59
View File
@@ -0,0 +1,59 @@
/*
* Pic.cpp
* Legacy 8259 PIC disable
* Copyright (c) 2025 Daniel Hammer
*/
#include "Pic.hpp"
#include <Io/IoPort.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
namespace Hal {
// 8259 PIC ports
constexpr uint16_t PIC1_COMMAND = 0x20;
constexpr uint16_t PIC1_DATA = 0x21;
constexpr uint16_t PIC2_COMMAND = 0xA0;
constexpr uint16_t PIC2_DATA = 0xA1;
// ICW1 flags
constexpr uint8_t ICW1_INIT = 0x11;
// ICW4 flags
constexpr uint8_t ICW4_8086 = 0x01;
void DisableLegacyPic() {
// Remap the PIC to vectors 0xF0-0xF7 (master) and 0xF8-0xFF (slave)
// so they don't conflict with CPU exceptions or our APIC vectors.
// Then mask all IRQs.
// ICW1: begin initialization sequence
Io::Out8(ICW1_INIT, PIC1_COMMAND);
Io::IoPortWait();
Io::Out8(ICW1_INIT, PIC2_COMMAND);
Io::IoPortWait();
// ICW2: remap IRQ base offsets
Io::Out8(0xF0, PIC1_DATA); // Master offset
Io::IoPortWait();
Io::Out8(0xF8, PIC2_DATA); // Slave offset
Io::IoPortWait();
// ICW3: cascade wiring
Io::Out8(0x04, PIC1_DATA); // Slave on IRQ2
Io::IoPortWait();
Io::Out8(0x02, PIC2_DATA); // Cascade identity
Io::IoPortWait();
// ICW4: 8086 mode
Io::Out8(ICW4_8086, PIC1_DATA);
Io::IoPortWait();
Io::Out8(ICW4_8086, PIC2_DATA);
Io::IoPortWait();
// Mask all IRQs on both PICs
Io::Out8(0xFF, PIC1_DATA);
Io::Out8(0xFF, PIC2_DATA);
Kt::KernelLogStream(Kt::OK, "PIC") << "Legacy 8259 PIC disabled";
}
};
+11
View File
@@ -0,0 +1,11 @@
/*
* Pic.hpp
* Legacy 8259 PIC disable
* Copyright (c) 2025 Daniel Hammer
*/
#pragma once
namespace Hal {
void DisableLegacyPic();
};
+5 -1
View File
@@ -111,7 +111,7 @@ namespace Hal {
void IDTInitialize() {
IDT = (InterruptDescriptor*)Memory::g_pfa->Allocate();
Kt::KernelLogStream(Kt::DEBUG, "IDT") << "Allocated IDT at " << base::hex << (uint64_t)IDT;
IDTR.Limit = 0x0FF;
IDTR.Limit = (256 * sizeof(InterruptDescriptor)) - 1;
IDTR.Base = (uint64_t)IDT;
Kt::KernelLogStream(Kt::DEBUG, "IDT") << "Set IDTR Base to " << base::hex << IDTR.Base << " and Limit to " << base::hex << IDTR.Limit;
@@ -123,4 +123,8 @@ namespace Hal {
Kt::KernelLogStream(Kt::OK, "Hal") << "Loaded new IDT";
}
void IDTReload() {
LoadIDT(IDTR);
}
};
+3
View File
@@ -6,6 +6,7 @@
#pragma once
#include <cstdint>
#include <cstddef>
namespace Hal {
struct InterruptDescriptor {
@@ -24,4 +25,6 @@ namespace Hal {
}__attribute__((packed));
void IDTInitialize();
void IDTEncodeInterrupt(std::size_t i, void* handler, uint8_t type_attr);
void IDTReload();
};