Restructured and rewritten entire codebase

This commit is contained in:
Alex
2023-10-09 01:16:24 +03:00
parent 446a571018
commit 889e1522a3
484 changed files with 15683 additions and 14032 deletions

489
arch/amd64/cpu/apic.cpp Normal file
View File

@ -0,0 +1,489 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "apic.hpp"
#include <memory.hpp>
#include <acpi.hpp>
#include <uart.hpp>
#include <lock.hpp>
#include <cpu.hpp>
#include <smp.hpp>
#include <io.h>
#include "../../../kernel.h"
NewLock(APICLock);
using namespace CPU::x64;
using namespace CPU::x86;
/*
In constructor APIC::APIC::APIC(int):
warning: left shift count >= width of type
| APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u;
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
*/
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
namespace APIC
{
// headache
// https://www.amd.com/system/files/TechDocs/24593.pdf
// https://www.naic.edu/~phil/software/intel/318148.pdf
uint32_t APIC::Read(uint32_t Register)
{
#ifdef DEBUG
if (Register != APIC_ICRLO &&
Register != APIC_ICRHI &&
Register != APIC_ID)
debug("APIC::Read(%#lx) [x2=%d]",
Register, x2APICSupported ? 1 : 0);
#endif
if (x2APICSupported)
assert(false);
CPU::MemBar::Barrier();
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
CPU::MemBar::Barrier();
return ret;
}
void APIC::Write(uint32_t Register, uint32_t Value)
{
#ifdef DEBUG
if (Register != APIC_EOI &&
Register != APIC_TDCR &&
Register != APIC_TIMER &&
Register != APIC_TICR &&
Register != APIC_ICRLO &&
Register != APIC_ICRHI)
debug("APIC::Write(%#lx, %#lx) [x2=%d]",
Register, Value, x2APICSupported ? 1 : 0);
#endif
if (x2APICSupported)
assert(false);
CPU::MemBar::Barrier();
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
CPU::MemBar::Barrier();
}
void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value)
{
debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value);
CPU::MemBar::Barrier();
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
CPU::MemBar::Barrier();
*((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value;
CPU::MemBar::Barrier();
}
uint32_t APIC::IORead(uint64_t Base, uint32_t Register)
{
debug("APIC::IORead(%#lx, %#lx)", Base, Register);
CPU::MemBar::Barrier();
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
CPU::MemBar::Barrier();
uint32_t ret = *((volatile uint32_t *)(((uintptr_t)Base + 16)));
CPU::MemBar::Barrier();
return ret;
}
void APIC::EOI()
{
if (this->x2APICSupported)
wrmsr(MSR_X2APIC_EOI, 0);
else
this->Write(APIC_EOI, 0);
}
void APIC::WaitForIPI()
{
if (this->x2APICSupported)
{
ErrorStatusRegister esr{};
esr.raw = uint32_t(rdmsr(MSR_X2APIC_ESR));
UNUSED(esr);
/* FIXME: Not sure if this is required or
how to implement it. */
}
else
{
InterruptCommandRegister icr{};
do
{
icr.split.Low = this->Read(APIC_ICRLO);
CPU::Pause();
} while (icr.DS != Idle);
}
}
void APIC::ICR(InterruptCommandRegister icr)
{
SmartCriticalSection(APICLock);
if (x2APICSupported)
{
assert(icr.MT != LowestPriority);
assert(icr.MT != DeliveryMode);
assert(icr.MT != ExtINT);
wrmsr(MSR_X2APIC_ICR, icr.raw);
this->WaitForIPI();
}
else
{
this->Write(APIC_ICRHI, icr.split.High);
this->Write(APIC_ICRLO, icr.split.Low);
this->WaitForIPI();
}
}
void APIC::SendInitIPI(int CPU)
{
SmartCriticalSection(APICLock);
InterruptCommandRegister icr{};
if (x2APICSupported)
{
icr.x2.MT = INIT;
icr.x2.L = Assert;
icr.x2.DES = uint8_t(CPU);
wrmsr(MSR_X2APIC_ICR, icr.raw);
this->WaitForIPI();
}
else
{
icr.MT = INIT;
icr.L = Assert;
icr.DES = uint8_t(CPU);
this->Write(APIC_ICRHI, icr.split.High);
this->Write(APIC_ICRLO, icr.split.Low);
this->WaitForIPI();
}
}
void APIC::SendStartupIPI(int CPU, uint64_t StartupAddress)
{
SmartCriticalSection(APICLock);
InterruptCommandRegister icr{};
if (x2APICSupported)
{
icr.x2.VEC = s_cst(uint8_t, StartupAddress >> 12);
icr.x2.MT = Startup;
icr.x2.L = Assert;
icr.x2.DES = uint8_t(CPU);
wrmsr(MSR_X2APIC_ICR, icr.raw);
this->WaitForIPI();
}
else
{
icr.VEC = s_cst(uint8_t, StartupAddress >> 12);
icr.MT = Startup;
icr.L = Assert;
icr.DES = uint8_t(CPU);
this->Write(APIC_ICRHI, icr.split.High);
this->Write(APIC_ICRLO, icr.split.Low);
this->WaitForIPI();
}
}
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
{
ACPI::MADT::MADTIOApic *ioapic = ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID];
uint32_t TableAddress = (this->IORead(ioapic->Address, GetIOAPICVersion));
IOAPICVersion ver = {.raw = TableAddress};
return ver.MLE + 1;
}
void APIC::RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, uint8_t CPU, int Status)
{
int64_t IOAPICTarget = -1;
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
for (size_t i = 0; i < madt->ioapic.size(); i++)
{
if (madt->ioapic[i]->GSIBase <= GSI)
{
if (madt->ioapic[i]->GSIBase + IOGetMaxRedirect(uint32_t(i)) > GSI)
{
IOAPICTarget = i;
break;
}
}
}
if (IOAPICTarget == -1)
{
error("No ISO table found for I/O APIC");
return;
}
IOAPICRedirectEntry Entry{};
Entry.VEC = Vector;
Entry.DES = CPU;
if (Flags & ActiveHighLow)
Entry.IPP = 1;
if (Flags & EdgeLevel)
Entry.TGM = 1;
if (!Status)
Entry.M = 1;
uint32_t IORegister = (GSI - madt->ioapic[IOAPICTarget]->GSIBase) * 2 + 16;
this->IOWrite(madt->ioapic[IOAPICTarget]->Address,
IORegister, Entry.split.Low);
this->IOWrite(madt->ioapic[IOAPICTarget]->Address,
IORegister + 1, Entry.split.High);
}
void APIC::RedirectIRQ(uint8_t CPU, uint8_t IRQ, int Status)
{
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
for (uint64_t i = 0; i < madt->iso.size(); i++)
if (madt->iso[i]->IRQSource == IRQ)
{
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
i, madt->iso[i]->IRQSource, madt->iso[i]->GSI, CPU);
this->RawRedirectIRQ(madt->iso[i]->IRQSource + 0x20,
madt->iso[i]->GSI,
madt->iso[i]->Flags,
CPU, Status);
return;
}
debug("Mapping IRQ%d on CPU %d", IRQ, CPU);
this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status);
}
void APIC::RedirectIRQs(uint8_t CPU)
{
SmartCriticalSection(APICLock);
debug("Redirecting IRQs...");
for (uint8_t i = 0; i < 16; i++)
this->RedirectIRQ(CPU, i, 1);
debug("Redirecting IRQs completed.");
}
APIC::APIC(int Core)
{
SmartCriticalSection(APICLock);
APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)};
uint64_t BaseLow = BaseStruct.ABALow;
uint64_t BaseHigh = BaseStruct.ABAHigh;
this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u;
trace("APIC Address: %#lx", this->APICBaseAddress);
Memory::Virtual().Map((void *)this->APICBaseAddress,
(void *)this->APICBaseAddress,
Memory::RW | Memory::PCD);
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
{
CPU::x86::AMD::CPUID0x00000001 cpuid;
cpuid.Get();
if (cpuid.ECX.x2APIC)
{
this->x2APICSupported = cpuid.ECX.x2APIC;
debug("x2APIC is supported");
}
}
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
{
CPU::x86::Intel::CPUID0x00000001 cpuid;
cpuid.Get();
if (cpuid.ECX.x2APIC)
{
this->x2APICSupported = cpuid.ECX.x2APIC;
debug("x2APIC is supported");
}
}
BaseStruct.AE = 1;
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
if (this->x2APICSupported)
{
BaseStruct.EXTD = 1;
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
}
if (!this->x2APICSupported)
{
this->Write(APIC_TPR, 0x0);
this->Write(APIC_DFR, 0xF0000000);
this->Write(APIC_LDR, this->Read(APIC_ID));
}
else
{
wrmsr(MSR_X2APIC_TPR, 0x0);
}
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
for (size_t i = 0; i < madt->nmi.size(); i++)
{
if (madt->nmi[i]->processor != 0xFF &&
Core != madt->nmi[i]->processor)
break;
uint32_t nmi = 0x402;
if (madt->nmi[i]->flags & 2)
nmi |= 1 << 13;
if (madt->nmi[i]->flags & 8)
nmi |= 1 << 15;
if (madt->nmi[i]->lint == 0)
{
if (this->x2APICSupported)
wrmsr(MSR_X2APIC_LVT_LINT0, nmi);
else
this->Write(APIC_LINT0, nmi);
}
else if (madt->nmi[i]->lint == 1)
{
if (this->x2APICSupported)
wrmsr(MSR_X2APIC_LVT_LINT1, nmi);
else
this->Write(APIC_LINT1, nmi);
}
}
/* Setup the spurious interrupt vector */
Spurious svr{};
if (this->x2APICSupported)
svr.raw = uint32_t(rdmsr(MSR_X2APIC_SIVR));
else
svr.raw = this->Read(APIC_SVR);
svr.VEC = IRQ223;
svr.ASE = 1;
if (this->x2APICSupported)
wrmsr(MSR_X2APIC_SIVR, svr.raw);
else
this->Write(APIC_SVR, svr.raw);
static int once = 0;
if (!once++)
{
// Disable PIT
outb(0x43, 0x28);
outb(0x40, 0x0);
// Disable PIC
outb(0x21, 0xFF);
outb(0xA1, 0xFF);
}
}
APIC::~APIC() {}
void Timer::OnInterruptReceived(TrapFrame *Frame) { UNUSED(Frame); }
void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
{
SmartCriticalSection(APICLock);
LVTTimer timer{};
timer.VEC = uint8_t(Vector);
timer.TMM = LVTTimerMode::OneShot;
LVTTimerDivide Divider = DivideBy8;
if (unlikely(strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0))
Divider = DivideBy128;
if (this->lapic->x2APIC)
{
// wrmsr(MSR_X2APIC_DIV_CONF, Divider); <- gpf on real hardware
wrmsr(MSR_X2APIC_INIT_COUNT, uint32_t(Ticks * Miliseconds));
wrmsr(MSR_X2APIC_LVT_TIMER, uint32_t(timer.raw));
}
else
{
this->lapic->Write(APIC_TDCR, Divider);
this->lapic->Write(APIC_TICR, uint32_t(Ticks * Miliseconds));
this->lapic->Write(APIC_TIMER, uint32_t(timer.raw));
}
}
Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */
{
SmartCriticalSection(APICLock);
this->lapic = apic;
LVTTimerDivide Divider = DivideBy8;
trace("Initializing APIC timer on CPU %d",
GetCurrentCPU()->ID);
if (this->lapic->x2APIC)
{
wrmsr(MSR_X2APIC_DIV_CONF, Divider);
wrmsr(MSR_X2APIC_INIT_COUNT, 0xFFFFFFFF);
}
else
{
this->lapic->Write(APIC_TDCR, Divider);
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
}
TimeManager->Sleep(1, Time::Units::Milliseconds);
// Mask the timer
if (this->lapic->x2APIC)
{
wrmsr(MSR_X2APIC_LVT_TIMER, 0x10000 /* LVTTimer.Mask flag */);
Ticks = 0xFFFFFFFF - rdmsr(MSR_X2APIC_CUR_COUNT);
}
else
{
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
}
// Config for IRQ0 timer
LVTTimer timer{};
timer.VEC = IRQ0;
timer.M = Unmasked;
timer.TMM = LVTTimerMode::OneShot;
// Initialize APIC timer
if (this->lapic->x2APIC)
{
wrmsr(MSR_X2APIC_DIV_CONF, Divider);
wrmsr(MSR_X2APIC_INIT_COUNT, Ticks);
wrmsr(MSR_X2APIC_LVT_TIMER, timer.raw);
}
else
{
this->lapic->Write(APIC_TDCR, Divider);
this->lapic->Write(APIC_TICR, uint32_t(Ticks));
this->lapic->Write(APIC_TIMER, uint32_t(timer.raw));
}
trace("%d APIC Timer %d ticks in.",
GetCurrentCPU()->ID, Ticks);
KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks);
}
Timer::~Timer()
{
}
}

386
arch/amd64/cpu/apic.hpp Normal file
View File

@ -0,0 +1,386 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_APIC_H__
#define __FENNIX_KERNEL_APIC_H__
#include <types.h>
#include <ints.hpp>
#include <cpu.hpp>
namespace APIC
{
enum APICRegisters
{
/* APIC ID Register */
APIC_ID = 0x20,
/* APIC Version Register */
APIC_VER = 0x30,
/* Task Priority Register (TPR) */
APIC_TPR = 0x80,
/* Arbitration Priority Register (APR) */
APIC_APR = 0x90,
/* Processor Priority Register (PPR) */
APIC_PPR = 0xA0,
/* End of Interrupt Register (EOI) */
APIC_EOI = 0xB0,
/* Remote Read Register */
APIC_RRD = 0xC0,
/* Logical Destination Register (LDR) */
APIC_LDR = 0xD0,
/* Destination Format Register (DFR) */
APIC_DFR = 0xE0,
/* Spurious Interrupt Vector Register */
APIC_SVR = 0xF0,
/* In-Service Register (ISR) */
APIC_ISR = 0x100,
/* Trigger Mode Register (TMR) */
APIC_TMR = 0x180,
/* Interrupt Request Register (IRR) */
APIC_IRR = 0x200,
/* Error Status Register (ESR) */
APIC_ESR = 0x280,
/* Interrupt Command Register Low (bits 31:0) */
APIC_ICRLO = 0x300,
/* Interrupt Command Register High (bits 63:32) */
APIC_ICRHI = 0x310,
/* Timer Local Vector Table Entry */
APIC_TIMER = 0x320,
/* Thermal Local Vector Table Entry */
APIC_THERMAL = 0x330,
/* Performance Counter Local Vector Table Entry */
APIC_PERF = 0x340,
/* Local Interrupt 0 Vector Table Entry */
APIC_LINT0 = 0x350,
/* Local Interrupt 1 Vector Table Entry */
APIC_LINT1 = 0x360,
/* Error Vector Table Entry */
APIC_ERROR = 0x370,
/* Timer Initial Count Register */
APIC_TICR = 0x380,
/* Timer Current Count Register */
APIC_TCCR = 0x390,
/* Timer Divide Configuration Register */
APIC_TDCR = 0x3E0,
/* Extended APIC Feature Register */
APIC_EFR = 0x400,
/* Extended APIC Control Register */
APIC_ECR = 0x410,
/* Specific End of Interrupt Register (SEOI) */
APIC_SEOI = 0x420,
/* Interrupt Enable Registers (IER) */
APIC_IER0 = 0x480,
/* Extended Interrupt [3:0] Local Vector Table Registers */
APIC_EILVT0 = 0x500,
};
enum IOAPICRegisters
{
GetIOAPICVersion = 0x1
};
enum IOAPICFlags
{
ActiveHighLow = 2,
EdgeLevel = 8
};
enum APICMessageType
{
Fixed = 0b000,
LowestPriority = 0b001, /* Reserved */
SMI = 0b010,
DeliveryMode = 0b011, /* Reserved */
NMI = 0b100,
INIT = 0b101,
Startup = 0b110,
ExtINT = 0b111 /* Reserved */
};
enum APICDestinationMode
{
Physical = 0b0,
Logical = 0b1
};
enum APICDeliveryStatus
{
Idle = 0b0,
SendPending = 0b1
};
enum APICLevel
{
DeAssert = 0b0,
Assert = 0b1
};
enum APICTriggerMode
{
Edge = 0b0,
Level = 0b1
};
enum APICDestinationShorthand
{
NoShorthand = 0b00,
Self = 0b01,
AllIncludingSelf = 0b10,
AllExcludingSelf = 0b11
};
enum LVTTimerDivide
{
DivideBy2 = 0b000,
DivideBy4 = 0b001,
DivideBy8 = 0b010,
DivideBy16 = 0b011,
DivideBy32 = 0b100,
DivideBy64 = 0b101,
DivideBy128 = 0b110,
DivideBy1 = 0b111
};
enum LVTTimerMask
{
Unmasked = 0b0,
Masked = 0b1
};
enum LVTTimerMode
{
OneShot = 0b00,
Periodic = 0b01,
TSCDeadline = 0b10
};
typedef union
{
struct
{
/** Vector */
uint64_t VEC : 8;
/** Reserved */
uint64_t Reserved0 : 4;
/** Delivery Status */
uint64_t DS : 1;
/** Reserved */
uint64_t Reserved1 : 3;
/** Mask */
uint64_t M : 1;
/** Timer Mode */
uint64_t TMM : 1;
/** Reserved */
uint64_t Reserved2 : 14;
};
uint32_t raw;
} __packed LVTTimer;
typedef union
{
struct
{
/** Vector */
uint64_t VEC : 8;
/** APIC Software Enable */
uint64_t ASE : 1;
/** Focus CPU Core Checking */
uint64_t FCC : 1;
/** Reserved */
uint64_t Reserved0 : 22;
};
uint32_t raw;
} __packed Spurious;
typedef union
{
struct
{
/** Vector */
uint64_t VEC : 8;
/** Message Type */
uint64_t MT : 3;
/** Destination Mode */
uint64_t DM : 1;
/** Delivery Status */
uint64_t DS : 1;
/** Reserved */
uint64_t Reserved0 : 1;
/** Level */
uint64_t L : 1;
/** Trigger Mode */
uint64_t TGM : 1;
/** Remote Read Status */
uint64_t RSS : 2;
/** Destination Shorthand */
uint64_t DSH : 2;
/** Reserved */
uint64_t Reserved2 : 36;
/** Destination */
uint64_t DES : 8;
};
struct
{
/** Vector */
uint64_t VEC : 8;
/** Message Type */
uint64_t MT : 3;
/** Destination Mode */
uint64_t DM : 1;
/** Reserved */
uint64_t Reserved0 : 2;
/** Level */
uint64_t L : 1;
/** Trigger Mode */
uint64_t TGM : 1;
/** Reserved */
uint64_t Reserved1 : 2;
/** Destination Shorthand */
uint64_t DSH : 2;
/** Reserved */
uint64_t Reserved2 : 12;
/** Destination */
uint64_t DES : 32;
} x2;
struct
{
uint32_t Low;
uint32_t High;
} split;
uint64_t raw;
} __packed InterruptCommandRegister;
typedef union
{
struct
{
/** Reserved */
uint64_t Reserved0 : 2;
/** Sent Accept Error */
uint64_t SAE : 1;
/** Receive Accept Error */
uint64_t RAE : 1;
/** Reserved */
uint64_t Reserved1 : 1;
/** Sent Illegal Vector */
uint64_t SIV : 1;
/** Received Illegal Vector */
uint64_t RIV : 1;
/** Illegal Register Address */
uint64_t IRA : 1;
/** Reserved */
uint64_t Reserved2 : 24;
};
uint32_t raw;
} ErrorStatusRegister;
typedef union
{
struct
{
/** Interrupt Vector */
uint64_t VEC : 8;
/** Delivery Mode */
uint64_t MT : 3;
/** Destination Mode */
uint64_t DM : 1;
/** Delivery Status */
uint64_t DS : 1;
/** Interrupt Input Pin Polarity */
uint64_t IPP : 1;
/** Remote IRR */
uint64_t RIR : 1;
/** Trigger Mode */
uint64_t TGM : 1;
/** Mask */
uint64_t M : 1;
/** Reserved */
uint64_t Reserved0 : 15;
/** Reserved */
uint64_t Reserved1 : 24;
/** Destination */
uint64_t DES : 8;
};
struct
{
uint32_t Low;
uint32_t High;
} split;
uint64_t raw;
} __packed IOAPICRedirectEntry;
typedef union
{
struct
{
/** Version */
uint64_t VER : 8;
/** Reserved */
uint64_t Reserved0 : 8;
/** Max LVT Entries */
uint64_t MLE : 8;
/** Reserved */
uint64_t Reserved1 : 7;
/** Extended APIC Register Space Present */
uint64_t EAS : 1;
};
uint32_t raw;
} __packed IOAPICVersion;
class APIC
{
private:
bool x2APICSupported = false;
uint64_t APICBaseAddress = 0;
public:
decltype(x2APICSupported) &x2APIC = x2APICSupported;
uint32_t Read(uint32_t Register);
void Write(uint32_t Register, uint32_t Value);
void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
uint32_t IORead(uint64_t Base, uint32_t Register);
void EOI();
void RedirectIRQs(uint8_t CPU = 0);
void WaitForIPI();
void ICR(InterruptCommandRegister icr);
void SendInitIPI(int CPU);
void SendStartupIPI(int CPU, uint64_t StartupAddress);
uint32_t IOGetMaxRedirect(uint32_t APICID);
void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, uint8_t CPU, int Status);
void RedirectIRQ(uint8_t CPU, uint8_t IRQ, int Status);
APIC(int Core);
~APIC();
};
class Timer : public Interrupts::Handler
{
private:
APIC *lapic;
uint64_t Ticks = 0;
void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
public:
uint64_t GetTicks() { return Ticks; }
void OneShot(uint32_t Vector, uint64_t Miliseconds);
Timer(APIC *apic);
~Timer();
};
}
#endif // !__FENNIX_KERNEL_APIC_H__

216
arch/amd64/cpu/gdt.cpp Normal file
View File

@ -0,0 +1,216 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "gdt.hpp"
#include <memory.hpp>
#include <smp.hpp>
#include <cpu.hpp>
#include <debug.h>
namespace GlobalDescriptorTable
{
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null = 0,
.Code = {
.SegmentLimitLow = 0xFFFF,
.BaseAddressLow = 0x0,
.BaseAddressHigh = 0x0,
.Accessed = 0,
.Readable = 1,
.Conforming = 0,
.Executable = 1,
.Type = 1,
.DescriptorPrivilegeLevel = 0,
.Present = 1,
.SegmentLimitHigh = 0xF,
.Available = 0,
.Long = 1,
.Default = 0,
.Granularity = 1,
.BaseAddressHigher = 0x0,
},
.Data = {
.SegmentLimitLow = 0xFFFF,
.BaseAddressLow = 0x0,
.BaseAddressHigh = 0x0,
.Accessed = 0,
.Writable = 1,
.ExpandDown = 0,
.Executable = 0,
.Type = 1,
.DescriptorPrivilegeLevel = 0,
.Present = 1,
.SegmentLimitHigh = 0xF,
.Available = 0,
.Reserved = 0,
.Default = 0,
.Granularity = 1,
.BaseAddressHigher = 0x0,
},
.UserData = {
.SegmentLimitLow = 0xFFFF,
.BaseAddressLow = 0x0,
.BaseAddressHigh = 0x0,
.Accessed = 0,
.Writable = 1,
.ExpandDown = 1,
.Executable = 0,
.Type = 1,
.DescriptorPrivilegeLevel = 3,
.Present = 1,
.SegmentLimitHigh = 0xF,
.Available = 0,
.Reserved = 0,
.Default = 0,
.Granularity = 1,
.BaseAddressHigher = 0x0,
},
.UserCode = {
.SegmentLimitLow = 0xFFFF,
.BaseAddressLow = 0x0,
.BaseAddressHigh = 0x0,
.Accessed = 0,
.Readable = 1,
.Conforming = 0,
.Executable = 1,
.Type = 1,
.DescriptorPrivilegeLevel = 3,
.Present = 1,
.SegmentLimitHigh = 0xF,
.Available = 0,
.Long = 1,
.Default = 0,
.Granularity = 1,
.BaseAddressHigher = 0x0,
},
.TaskStateSegment{},
};
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
TaskStateSegment tss[MAX_CPU] = {
0,
{0, 0, 0},
0,
{0, 0, 0, 0, 0, 0, 0},
0,
0,
0,
};
void *CPUStackPointer[MAX_CPU];
SafeFunction void Init(int Core)
{
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
gdt[Core] =
{
.Limit = sizeof(GlobalDescriptorTableEntries) - 1,
.BaseAddress = &GDTEntries[Core],
};
debug("GDT: %#lx", &gdt[Core]);
debug("GDT KERNEL CODE %#lx", GDT_KERNEL_CODE);
debug("GDT KERNEL DATA %#lx", GDT_KERNEL_DATA);
debug("GDT USER CODE %#lx", GDT_USER_CODE);
debug("GDT USER DATA %#lx", GDT_USER_DATA);
debug("GDT TSS %#lx", GDT_TSS);
CPU::x64::lgdt(&gdt[Core]);
asmv("movq %%rsp, %%rax\n"
"pushq $16\n"
"pushq %%rax\n"
"pushfq\n"
"pushq $8\n"
"pushq $1f\n"
"iretq\n"
"1:\n"
"movw $16, %%ax\n"
"movw %%ax, %%ds\n"
"movw %%ax, %%es\n" ::
: "memory", "rax");
CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
memset(CPUStackPointer[Core], 0, STACK_SIZE);
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
TO_PAGES(STACK_SIZE + 1));
uintptr_t Base = (uintptr_t)&tss[Core];
size_t Limit = Base + sizeof(TaskStateSegment);
SystemSegmentDescriptor *tssDesc = &gdt[Core].BaseAddress->TaskStateSegment;
tssDesc->SegmentLimitLow = Limit & 0xFFFF;
tssDesc->BaseAddressLow = Base & 0xFFFF;
tssDesc->BaseAddressMiddle = (Base >> 16) & 0xFF;
tssDesc->Type = AVAILABLE_64BIT_TSS;
tssDesc->Zero0 = 0;
tssDesc->DescriptorPrivilegeLevel = 0;
tssDesc->Present = 1;
tssDesc->Available = 0;
tssDesc->Reserved0 = 0;
tssDesc->Granularity = 0;
tssDesc->BaseAddressHigh = (Base >> 24) & 0xFF;
tssDesc->BaseAddressHigher = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
tssDesc->Reserved1 = 0;
tssDesc->Zero1 = 0;
tssDesc->Reserved2 = 0;
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0;
for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++)
{
void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE;
memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE);
debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE);
}
CPU::x64::ltr(GDT_TSS);
debug("Global Descriptor Table initialized");
}
SafeFunction void SetKernelStack(void *Stack)
{
long CPUID = GetCurrentCPU()->ID;
if (Stack != nullptr)
tss[CPUID].StackPointer[0] = (uint64_t)Stack;
else
tss[CPUID].StackPointer[0] = (uint64_t)CPUStackPointer[CPUID] + STACK_SIZE;
/*
FIXME: There's a bug in kernel which if
we won't update "tss[CPUID].StackPointer[0]"
with the current stack pointer, the kernel
will crash.
*/
asmv("mov %%rsp, %0"
: "=r"(tss[CPUID].StackPointer[0]));
}
void *GetKernelStack() { return (void *)tss[GetCurrentCPU()->ID].StackPointer[0]; }
}

67
arch/amd64/cpu/gdt.hpp Normal file
View File

@ -0,0 +1,67 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_GDT_H__
#define __FENNIX_KERNEL_GDT_H__
#include <types.h>
#include <cpu/x86/x64/SegmentDescriptors.hpp>
namespace GlobalDescriptorTable
{
struct TaskStateSegment
{
uint32_t Reserved0 __aligned(16);
uint64_t StackPointer[3];
uint64_t Reserved1;
uint64_t InterruptStackTable[7];
uint64_t Reserved2;
uint16_t Reserved3;
uint16_t IOMapBaseAddressOffset;
} __packed;
struct GlobalDescriptorTableEntries
{
uint64_t Null;
CodeSegmentDescriptor Code;
DataSegmentDescriptor Data;
DataSegmentDescriptor UserData;
CodeSegmentDescriptor UserCode;
SystemSegmentDescriptor TaskStateSegment;
} __packed;
struct GlobalDescriptorTableDescriptor
{
uint16_t Limit;
GlobalDescriptorTableEntries *BaseAddress;
} __packed;
extern void *CPUStackPointer[];
extern TaskStateSegment tss[];
void Init(int Core);
void SetKernelStack(void *Stack);
void *GetKernelStack();
}
#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)
#define GDT_KERNEL_DATA offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Data)
#define GDT_USER_CODE (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserCode) | 3)
#define GDT_USER_DATA (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserData) | 3)
#define GDT_TSS (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, TaskStateSegment) | 3)
#endif // !__FENNIX_KERNEL_GDT_H__

809
arch/amd64/cpu/idt.cpp Normal file
View File

@ -0,0 +1,809 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "idt.hpp"
#include <memory.hpp>
#include <cpu.hpp>
#include <debug.h>
#include <io.h>
#include "gdt.hpp"
#include "../../../kernel.h"
/* conversion from uint64_t {aka long unsigned int} to unsigned char:2 may change value */
#pragma GCC diagnostic ignored "-Wconversion"
extern "C" void MainInterruptHandler(void *Data);
extern "C" void ExceptionHandler(void *Data);
namespace InterruptDescriptorTable
{
__aligned(8) static IDTGateDescriptor Entries[0x100];
__aligned(8) IDTRegister IDTr = {
.Limit = sizeof(Entries) - 1,
.BaseAddress = Entries,
};
void SetEntry(uint8_t Index,
void (*Base)(),
InterruptStackTableType InterruptStackTable,
GateType Gate,
PrivilegeLevelType Ring,
bool Present,
uint16_t SegmentSelector)
{
switch (Gate)
{
case CALL_GATE_64BIT:
{
CallGate gate{
.TargetOffsetLow = s_cst(uint16_t, ((uint64_t)Base & 0xFFFF)),
.TargetSelector = SegmentSelector,
.Reserved0 = 0,
.Type = Gate,
.Zero0 = 0,
.DescriptorPrivilegeLevel = Ring,
.Present = Present,
.TargetOffsetMiddle = s_cst(uint16_t, ((uint64_t)Base >> 16)),
.TargetOffsetHigh = s_cst(uint32_t, ((uint64_t)Base >> 32)),
.Reserved1 = 0,
.Zero1 = 0,
.Reserved2 = 0,
};
Entries[Index].Call = gate;
break;
}
case INTERRUPT_GATE_64BIT:
{
InterruptGate gate{
.TargetOffsetLow = s_cst(uint16_t, ((uint64_t)Base & 0xFFFF)),
.TargetSelector = SegmentSelector,
.InterruptStackTable = InterruptStackTable,
.Reserved0 = 0,
.Type = Gate,
.Zero = 0,
.DescriptorPrivilegeLevel = Ring,
.Present = Present,
.TargetOffsetMiddle = s_cst(uint16_t, ((uint64_t)Base >> 16)),
.TargetOffsetHigh = s_cst(uint32_t, ((uint64_t)Base >> 32)),
.Reserved1 = 0,
};
Entries[Index].Interrupt = gate;
break;
}
case TRAP_GATE_64BIT:
{
TrapGate gate{
.TargetOffsetLow = s_cst(uint16_t, ((uint64_t)Base & 0xFFFF)),
.TargetSelector = SegmentSelector,
.InterruptStackTable = InterruptStackTable,
.Reserved0 = 0,
.Type = Gate,
.Zero = 0,
.DescriptorPrivilegeLevel = Ring,
.Present = Present,
.TargetOffsetMiddle = s_cst(uint16_t, ((uint64_t)Base >> 16)),
.TargetOffsetHigh = s_cst(uint32_t, ((uint64_t)Base >> 32)),
.Reserved1 = 0,
};
Entries[Index].Trap = gate;
break;
}
case LDT_64BIT:
case AVAILABLE_64BIT_TSS:
case BUSY_64BIT_TSS:
default:
{
assert(false);
break;
}
}
}
extern "C" __naked __used __no_stack_protector __aligned(16) void ExceptionHandlerStub()
{
asm("cld\n"
"cli\n"
"pushq %rax\n"
"pushq %rbx\n"
"pushq %rcx\n"
"pushq %rdx\n"
"pushq %rsi\n"
"pushq %rdi\n"
"pushq %rbp\n"
"pushq %r8\n"
"pushq %r9\n"
"pushq %r10\n"
"pushq %r11\n"
"pushq %r12\n"
"pushq %r13\n"
"pushq %r14\n"
"pushq %r15\n"
"movq %rsp, %rdi\n"
"call ExceptionHandler\n"
"popq %r15\n"
"popq %r14\n"
"popq %r13\n"
"popq %r12\n"
"popq %r11\n"
"popq %r10\n"
"popq %r9\n"
"popq %r8\n"
"popq %rbp\n"
"popq %rdi\n"
"popq %rsi\n"
"popq %rdx\n"
"popq %rcx\n"
"popq %rbx\n"
"popq %rax\n"
"addq $16, %rsp\n"
"iretq"); // pop CS RIP RFLAGS SS RSP
}
extern "C" __naked __used __no_stack_protector __aligned(16) void InterruptHandlerStub()
{
asm("cld\n"
"cli\n"
"pushq %rax\n"
"pushq %rbx\n"
"pushq %rcx\n"
"pushq %rdx\n"
"pushq %rsi\n"
"pushq %rdi\n"
"pushq %rbp\n"
"pushq %r8\n"
"pushq %r9\n"
"pushq %r10\n"
"pushq %r11\n"
"pushq %r12\n"
"pushq %r13\n"
"pushq %r14\n"
"pushq %r15\n"
"movq %rsp, %rdi\n"
"call MainInterruptHandler\n"
"popq %r15\n"
"popq %r14\n"
"popq %r13\n"
"popq %r12\n"
"popq %r11\n"
"popq %r10\n"
"popq %r9\n"
"popq %r8\n"
"popq %rbp\n"
"popq %rdi\n"
"popq %rsi\n"
"popq %rdx\n"
"popq %rcx\n"
"popq %rbx\n"
"popq %rax\n"
"addq $16, %rsp\n"
"sti\n"
"iretq"); // pop CS RIP RFLAGS SS RSP
}
#pragma region Exceptions
#define EXCEPTION_HANDLER(num) \
__naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
{ \
asm("pushq $0\npushq $" #num "\n" \
"jmp ExceptionHandlerStub"); \
}
#define EXCEPTION_ERROR_HANDLER(num) \
__naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
{ \
asm("pushq $" #num "\n" \
"jmp ExceptionHandlerStub"); \
}
#define INTERRUPT_HANDLER(num) \
__naked __used __no_stack_protector __aligned(16) void InterruptHandler_##num() \
{ \
asm("pushq $0\npushq $" #num "\n" \
"jmp InterruptHandlerStub\n"); \
}
/* ISR */
EXCEPTION_HANDLER(0x0);
EXCEPTION_HANDLER(0x1);
EXCEPTION_HANDLER(0x2);
EXCEPTION_HANDLER(0x3);
EXCEPTION_HANDLER(0x4);
EXCEPTION_HANDLER(0x5);
EXCEPTION_HANDLER(0x6);
EXCEPTION_HANDLER(0x7);
EXCEPTION_ERROR_HANDLER(0x8);
EXCEPTION_HANDLER(0x9);
EXCEPTION_ERROR_HANDLER(0xa);
EXCEPTION_ERROR_HANDLER(0xb);
EXCEPTION_ERROR_HANDLER(0xc);
EXCEPTION_ERROR_HANDLER(0xd);
EXCEPTION_ERROR_HANDLER(0xe);
EXCEPTION_HANDLER(0xf);
EXCEPTION_ERROR_HANDLER(0x10);
EXCEPTION_HANDLER(0x11);
EXCEPTION_HANDLER(0x12);
EXCEPTION_HANDLER(0x13);
EXCEPTION_HANDLER(0x14);
EXCEPTION_HANDLER(0x15);
EXCEPTION_HANDLER(0x16);
EXCEPTION_HANDLER(0x17);
EXCEPTION_HANDLER(0x18);
EXCEPTION_HANDLER(0x19);
EXCEPTION_HANDLER(0x1a);
EXCEPTION_HANDLER(0x1b);
EXCEPTION_HANDLER(0x1c);
EXCEPTION_HANDLER(0x1d);
EXCEPTION_HANDLER(0x1e);
EXCEPTION_HANDLER(0x1f);
/* IRQ */
INTERRUPT_HANDLER(0x20)
INTERRUPT_HANDLER(0x21)
INTERRUPT_HANDLER(0x22)
INTERRUPT_HANDLER(0x23)
INTERRUPT_HANDLER(0x24)
INTERRUPT_HANDLER(0x25)
INTERRUPT_HANDLER(0x26)
INTERRUPT_HANDLER(0x27)
INTERRUPT_HANDLER(0x28)
INTERRUPT_HANDLER(0x29)
INTERRUPT_HANDLER(0x2a)
INTERRUPT_HANDLER(0x2b)
INTERRUPT_HANDLER(0x2c)
INTERRUPT_HANDLER(0x2d)
INTERRUPT_HANDLER(0x2e)
INTERRUPT_HANDLER(0x2f)
/* Reserved by OS */
INTERRUPT_HANDLER(0x30)
INTERRUPT_HANDLER(0x31)
INTERRUPT_HANDLER(0x32)
INTERRUPT_HANDLER(0x33)
INTERRUPT_HANDLER(0x34)
INTERRUPT_HANDLER(0x35)
INTERRUPT_HANDLER(0x36)
INTERRUPT_HANDLER(0x37)
INTERRUPT_HANDLER(0x38)
INTERRUPT_HANDLER(0x39)
INTERRUPT_HANDLER(0x3a)
INTERRUPT_HANDLER(0x3b)
INTERRUPT_HANDLER(0x3c)
INTERRUPT_HANDLER(0x3d)
/* Free */
INTERRUPT_HANDLER(0x3e)
INTERRUPT_HANDLER(0x3f)
INTERRUPT_HANDLER(0x40)
INTERRUPT_HANDLER(0x41)
INTERRUPT_HANDLER(0x42)
INTERRUPT_HANDLER(0x43)
INTERRUPT_HANDLER(0x44)
INTERRUPT_HANDLER(0x45)
INTERRUPT_HANDLER(0x46)
INTERRUPT_HANDLER(0x47)
INTERRUPT_HANDLER(0x48)
INTERRUPT_HANDLER(0x49)
INTERRUPT_HANDLER(0x4a)
INTERRUPT_HANDLER(0x4b)
INTERRUPT_HANDLER(0x4c)
INTERRUPT_HANDLER(0x4d)
INTERRUPT_HANDLER(0x4e)
INTERRUPT_HANDLER(0x4f)
INTERRUPT_HANDLER(0x50)
INTERRUPT_HANDLER(0x51)
INTERRUPT_HANDLER(0x52)
INTERRUPT_HANDLER(0x53)
INTERRUPT_HANDLER(0x54)
INTERRUPT_HANDLER(0x55)
INTERRUPT_HANDLER(0x56)
INTERRUPT_HANDLER(0x57)
INTERRUPT_HANDLER(0x58)
INTERRUPT_HANDLER(0x59)
INTERRUPT_HANDLER(0x5a)
INTERRUPT_HANDLER(0x5b)
INTERRUPT_HANDLER(0x5c)
INTERRUPT_HANDLER(0x5d)
INTERRUPT_HANDLER(0x5e)
INTERRUPT_HANDLER(0x5f)
INTERRUPT_HANDLER(0x60)
INTERRUPT_HANDLER(0x61)
INTERRUPT_HANDLER(0x62)
INTERRUPT_HANDLER(0x63)
INTERRUPT_HANDLER(0x64)
INTERRUPT_HANDLER(0x65)
INTERRUPT_HANDLER(0x66)
INTERRUPT_HANDLER(0x67)
INTERRUPT_HANDLER(0x68)
INTERRUPT_HANDLER(0x69)
INTERRUPT_HANDLER(0x6a)
INTERRUPT_HANDLER(0x6b)
INTERRUPT_HANDLER(0x6c)
INTERRUPT_HANDLER(0x6d)
INTERRUPT_HANDLER(0x6e)
INTERRUPT_HANDLER(0x6f)
INTERRUPT_HANDLER(0x70)
INTERRUPT_HANDLER(0x71)
INTERRUPT_HANDLER(0x72)
INTERRUPT_HANDLER(0x73)
INTERRUPT_HANDLER(0x74)
INTERRUPT_HANDLER(0x75)
INTERRUPT_HANDLER(0x76)
INTERRUPT_HANDLER(0x77)
INTERRUPT_HANDLER(0x78)
INTERRUPT_HANDLER(0x79)
INTERRUPT_HANDLER(0x7a)
INTERRUPT_HANDLER(0x7b)
INTERRUPT_HANDLER(0x7c)
INTERRUPT_HANDLER(0x7d)
INTERRUPT_HANDLER(0x7e)
INTERRUPT_HANDLER(0x7f)
INTERRUPT_HANDLER(0x80)
INTERRUPT_HANDLER(0x81)
INTERRUPT_HANDLER(0x82)
INTERRUPT_HANDLER(0x83)
INTERRUPT_HANDLER(0x84)
INTERRUPT_HANDLER(0x85)
INTERRUPT_HANDLER(0x86)
INTERRUPT_HANDLER(0x87)
INTERRUPT_HANDLER(0x88)
INTERRUPT_HANDLER(0x89)
INTERRUPT_HANDLER(0x8a)
INTERRUPT_HANDLER(0x8b)
INTERRUPT_HANDLER(0x8c)
INTERRUPT_HANDLER(0x8d)
INTERRUPT_HANDLER(0x8e)
INTERRUPT_HANDLER(0x8f)
INTERRUPT_HANDLER(0x90)
INTERRUPT_HANDLER(0x91)
INTERRUPT_HANDLER(0x92)
INTERRUPT_HANDLER(0x93)
INTERRUPT_HANDLER(0x94)
INTERRUPT_HANDLER(0x95)
INTERRUPT_HANDLER(0x96)
INTERRUPT_HANDLER(0x97)
INTERRUPT_HANDLER(0x98)
INTERRUPT_HANDLER(0x99)
INTERRUPT_HANDLER(0x9a)
INTERRUPT_HANDLER(0x9b)
INTERRUPT_HANDLER(0x9c)
INTERRUPT_HANDLER(0x9d)
INTERRUPT_HANDLER(0x9e)
INTERRUPT_HANDLER(0x9f)
INTERRUPT_HANDLER(0xa0)
INTERRUPT_HANDLER(0xa1)
INTERRUPT_HANDLER(0xa2)
INTERRUPT_HANDLER(0xa3)
INTERRUPT_HANDLER(0xa4)
INTERRUPT_HANDLER(0xa5)
INTERRUPT_HANDLER(0xa6)
INTERRUPT_HANDLER(0xa7)
INTERRUPT_HANDLER(0xa8)
INTERRUPT_HANDLER(0xa9)
INTERRUPT_HANDLER(0xaa)
INTERRUPT_HANDLER(0xab)
INTERRUPT_HANDLER(0xac)
INTERRUPT_HANDLER(0xad)
INTERRUPT_HANDLER(0xae)
INTERRUPT_HANDLER(0xaf)
INTERRUPT_HANDLER(0xb0)
INTERRUPT_HANDLER(0xb1)
INTERRUPT_HANDLER(0xb2)
INTERRUPT_HANDLER(0xb3)
INTERRUPT_HANDLER(0xb4)
INTERRUPT_HANDLER(0xb5)
INTERRUPT_HANDLER(0xb6)
INTERRUPT_HANDLER(0xb7)
INTERRUPT_HANDLER(0xb8)
INTERRUPT_HANDLER(0xb9)
INTERRUPT_HANDLER(0xba)
INTERRUPT_HANDLER(0xbb)
INTERRUPT_HANDLER(0xbc)
INTERRUPT_HANDLER(0xbd)
INTERRUPT_HANDLER(0xbe)
INTERRUPT_HANDLER(0xbf)
INTERRUPT_HANDLER(0xc0)
INTERRUPT_HANDLER(0xc1)
INTERRUPT_HANDLER(0xc2)
INTERRUPT_HANDLER(0xc3)
INTERRUPT_HANDLER(0xc4)
INTERRUPT_HANDLER(0xc5)
INTERRUPT_HANDLER(0xc6)
INTERRUPT_HANDLER(0xc7)
INTERRUPT_HANDLER(0xc8)
INTERRUPT_HANDLER(0xc9)
INTERRUPT_HANDLER(0xca)
INTERRUPT_HANDLER(0xcb)
INTERRUPT_HANDLER(0xcc)
INTERRUPT_HANDLER(0xcd)
INTERRUPT_HANDLER(0xce)
INTERRUPT_HANDLER(0xcf)
INTERRUPT_HANDLER(0xd0)
INTERRUPT_HANDLER(0xd1)
INTERRUPT_HANDLER(0xd2)
INTERRUPT_HANDLER(0xd3)
INTERRUPT_HANDLER(0xd4)
INTERRUPT_HANDLER(0xd5)
INTERRUPT_HANDLER(0xd6)
INTERRUPT_HANDLER(0xd7)
INTERRUPT_HANDLER(0xd8)
INTERRUPT_HANDLER(0xd9)
INTERRUPT_HANDLER(0xda)
INTERRUPT_HANDLER(0xdb)
INTERRUPT_HANDLER(0xdc)
INTERRUPT_HANDLER(0xdd)
INTERRUPT_HANDLER(0xde)
INTERRUPT_HANDLER(0xdf)
INTERRUPT_HANDLER(0xe0)
INTERRUPT_HANDLER(0xe1)
INTERRUPT_HANDLER(0xe2)
INTERRUPT_HANDLER(0xe3)
INTERRUPT_HANDLER(0xe4)
INTERRUPT_HANDLER(0xe5)
INTERRUPT_HANDLER(0xe6)
INTERRUPT_HANDLER(0xe7)
INTERRUPT_HANDLER(0xe8)
INTERRUPT_HANDLER(0xe9)
INTERRUPT_HANDLER(0xea)
INTERRUPT_HANDLER(0xeb)
INTERRUPT_HANDLER(0xec)
INTERRUPT_HANDLER(0xed)
INTERRUPT_HANDLER(0xee)
INTERRUPT_HANDLER(0xef)
INTERRUPT_HANDLER(0xf0)
INTERRUPT_HANDLER(0xf1)
INTERRUPT_HANDLER(0xf2)
INTERRUPT_HANDLER(0xf3)
INTERRUPT_HANDLER(0xf4)
INTERRUPT_HANDLER(0xf5)
INTERRUPT_HANDLER(0xf6)
INTERRUPT_HANDLER(0xf7)
INTERRUPT_HANDLER(0xf8)
INTERRUPT_HANDLER(0xf9)
INTERRUPT_HANDLER(0xfa)
INTERRUPT_HANDLER(0xfb)
INTERRUPT_HANDLER(0xfc)
INTERRUPT_HANDLER(0xfd)
INTERRUPT_HANDLER(0xfe)
INTERRUPT_HANDLER(0xff)
#pragma endregion Exceptions
void Init(int Core)
{
if (Core == 0) /* Disable PIC using BSP */
{
// PIC
outb(0x20, 0x10 | 0x1);
outb(0x80, 0);
outb(0xA0, 0x10 | 0x10);
outb(0x80, 0);
outb(0x21, 0x20);
outb(0x80, 0);
outb(0xA1, 0x28);
outb(0x80, 0);
outb(0x21, 0x04);
outb(0x80, 0);
outb(0xA1, 0x02);
outb(0x80, 0);
outb(0x21, 1);
outb(0x80, 0);
outb(0xA1, 1);
outb(0x80, 0);
// Masking and disabling PIC
outb(0x21, 0xff);
outb(0x80, 0);
outb(0xA1, 0xff);
}
bool EnableISRs = true;
#ifdef DEBUG
EnableISRs = !DebuggerIsAttached;
if (!EnableISRs)
KPrint("\eFFA500The debugger is attached, disabling all ISRs.");
#endif
/* ISR */
SetEntry(0x0, InterruptHandler_0x0, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1, InterruptHandler_0x1, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x2, InterruptHandler_0x2, IST2, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x3, InterruptHandler_0x3, IST1, TRAP_GATE_64BIT, RING3, (!DebuggerIsAttached), GDT_KERNEL_CODE); /* Do not handle breakpoints if we are debugging the kernel. */
SetEntry(0x4, InterruptHandler_0x4, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x5, InterruptHandler_0x5, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x6, InterruptHandler_0x6, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x7, InterruptHandler_0x7, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x8, InterruptHandler_0x8, IST3, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x9, InterruptHandler_0x9, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0xa, InterruptHandler_0xa, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0xb, InterruptHandler_0xb, IST1, TRAP_GATE_64BIT, RING0, (!DebuggerIsAttached), GDT_KERNEL_CODE);
SetEntry(0xc, InterruptHandler_0xc, IST3, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0xd, InterruptHandler_0xd, IST3, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0xe, InterruptHandler_0xe, IST3, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0xf, InterruptHandler_0xf, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x10, InterruptHandler_0x10, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x11, InterruptHandler_0x11, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x12, InterruptHandler_0x12, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x13, InterruptHandler_0x13, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x14, InterruptHandler_0x14, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x15, InterruptHandler_0x15, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x16, InterruptHandler_0x16, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x17, InterruptHandler_0x17, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x18, InterruptHandler_0x18, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x19, InterruptHandler_0x19, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1a, InterruptHandler_0x1a, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1b, InterruptHandler_0x1b, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1c, InterruptHandler_0x1c, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1d, InterruptHandler_0x1d, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1e, InterruptHandler_0x1e, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1f, InterruptHandler_0x1f, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
/* IRQ */
SetEntry(0x20, InterruptHandler_0x20, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x21, InterruptHandler_0x21, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x22, InterruptHandler_0x22, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x23, InterruptHandler_0x23, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x24, InterruptHandler_0x24, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x25, InterruptHandler_0x25, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x26, InterruptHandler_0x26, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x27, InterruptHandler_0x27, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x28, InterruptHandler_0x28, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x29, InterruptHandler_0x29, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x2a, InterruptHandler_0x2a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x2b, InterruptHandler_0x2b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x2c, InterruptHandler_0x2c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x2d, InterruptHandler_0x2d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x2e, InterruptHandler_0x2e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x2f, InterruptHandler_0x2f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
/* Reserved by OS */
SetEntry(0x30, InterruptHandler_0x30, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x31, InterruptHandler_0x31, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x32, InterruptHandler_0x32, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x33, InterruptHandler_0x33, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x34, InterruptHandler_0x34, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x35, InterruptHandler_0x35, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x36, InterruptHandler_0x36, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x37, InterruptHandler_0x37, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x38, InterruptHandler_0x38, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x39, InterruptHandler_0x39, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x3a, InterruptHandler_0x3a, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x3b, InterruptHandler_0x3b, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x3c, InterruptHandler_0x3c, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x3d, InterruptHandler_0x3d, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
/* Free */
SetEntry(0x3e, InterruptHandler_0x3e, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x3f, InterruptHandler_0x3f, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x40, InterruptHandler_0x40, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x41, InterruptHandler_0x41, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x42, InterruptHandler_0x42, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x43, InterruptHandler_0x43, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x44, InterruptHandler_0x44, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x45, InterruptHandler_0x45, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x46, InterruptHandler_0x46, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x47, InterruptHandler_0x47, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x48, InterruptHandler_0x48, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x49, InterruptHandler_0x49, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x4a, InterruptHandler_0x4a, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x4b, InterruptHandler_0x4b, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x4c, InterruptHandler_0x4c, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x4d, InterruptHandler_0x4d, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x4e, InterruptHandler_0x4e, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x4f, InterruptHandler_0x4f, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x50, InterruptHandler_0x50, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x51, InterruptHandler_0x51, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x52, InterruptHandler_0x52, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x53, InterruptHandler_0x53, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x54, InterruptHandler_0x54, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x55, InterruptHandler_0x55, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x56, InterruptHandler_0x56, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x57, InterruptHandler_0x57, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x58, InterruptHandler_0x58, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x59, InterruptHandler_0x59, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x5a, InterruptHandler_0x5a, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x5b, InterruptHandler_0x5b, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x5c, InterruptHandler_0x5c, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x5d, InterruptHandler_0x5d, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x5e, InterruptHandler_0x5e, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x5f, InterruptHandler_0x5f, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x60, InterruptHandler_0x60, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x61, InterruptHandler_0x61, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x62, InterruptHandler_0x62, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x63, InterruptHandler_0x63, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x64, InterruptHandler_0x64, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x65, InterruptHandler_0x65, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x66, InterruptHandler_0x66, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x67, InterruptHandler_0x67, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x68, InterruptHandler_0x68, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x69, InterruptHandler_0x69, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x6a, InterruptHandler_0x6a, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x6b, InterruptHandler_0x6b, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x6c, InterruptHandler_0x6c, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x6d, InterruptHandler_0x6d, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x6e, InterruptHandler_0x6e, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x6f, InterruptHandler_0x6f, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x70, InterruptHandler_0x70, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x71, InterruptHandler_0x71, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x72, InterruptHandler_0x72, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x73, InterruptHandler_0x73, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x74, InterruptHandler_0x74, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x75, InterruptHandler_0x75, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x76, InterruptHandler_0x76, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x77, InterruptHandler_0x77, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x78, InterruptHandler_0x78, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x79, InterruptHandler_0x79, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x7a, InterruptHandler_0x7a, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x7b, InterruptHandler_0x7b, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x7c, InterruptHandler_0x7c, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x7d, InterruptHandler_0x7d, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x7e, InterruptHandler_0x7e, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x7f, InterruptHandler_0x7f, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x80, InterruptHandler_0x80, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x81, InterruptHandler_0x81, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x82, InterruptHandler_0x82, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x83, InterruptHandler_0x83, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x84, InterruptHandler_0x84, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x85, InterruptHandler_0x85, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x86, InterruptHandler_0x86, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x87, InterruptHandler_0x87, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x88, InterruptHandler_0x88, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x89, InterruptHandler_0x89, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x8a, InterruptHandler_0x8a, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x8b, InterruptHandler_0x8b, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x8c, InterruptHandler_0x8c, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x8d, InterruptHandler_0x8d, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x8e, InterruptHandler_0x8e, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x8f, InterruptHandler_0x8f, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x90, InterruptHandler_0x90, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x91, InterruptHandler_0x91, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x92, InterruptHandler_0x92, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x93, InterruptHandler_0x93, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x94, InterruptHandler_0x94, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x95, InterruptHandler_0x95, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x96, InterruptHandler_0x96, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x97, InterruptHandler_0x97, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x98, InterruptHandler_0x98, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x99, InterruptHandler_0x99, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x9a, InterruptHandler_0x9a, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x9b, InterruptHandler_0x9b, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x9c, InterruptHandler_0x9c, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x9d, InterruptHandler_0x9d, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x9e, InterruptHandler_0x9e, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0x9f, InterruptHandler_0x9f, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa0, InterruptHandler_0xa0, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa1, InterruptHandler_0xa1, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa2, InterruptHandler_0xa2, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa3, InterruptHandler_0xa3, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa4, InterruptHandler_0xa4, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa5, InterruptHandler_0xa5, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa6, InterruptHandler_0xa6, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa7, InterruptHandler_0xa7, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa8, InterruptHandler_0xa8, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xa9, InterruptHandler_0xa9, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xaa, InterruptHandler_0xaa, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xab, InterruptHandler_0xab, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xac, InterruptHandler_0xac, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xad, InterruptHandler_0xad, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xae, InterruptHandler_0xae, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xaf, InterruptHandler_0xaf, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb0, InterruptHandler_0xb0, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb1, InterruptHandler_0xb1, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb2, InterruptHandler_0xb2, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb3, InterruptHandler_0xb3, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb4, InterruptHandler_0xb4, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb5, InterruptHandler_0xb5, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb6, InterruptHandler_0xb6, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb7, InterruptHandler_0xb7, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb8, InterruptHandler_0xb8, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xb9, InterruptHandler_0xb9, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xba, InterruptHandler_0xba, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xbb, InterruptHandler_0xbb, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xbc, InterruptHandler_0xbc, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xbd, InterruptHandler_0xbd, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xbe, InterruptHandler_0xbe, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xbf, InterruptHandler_0xbf, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc0, InterruptHandler_0xc0, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc1, InterruptHandler_0xc1, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc2, InterruptHandler_0xc2, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc3, InterruptHandler_0xc3, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc4, InterruptHandler_0xc4, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc5, InterruptHandler_0xc5, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc6, InterruptHandler_0xc6, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc7, InterruptHandler_0xc7, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc8, InterruptHandler_0xc8, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xc9, InterruptHandler_0xc9, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xca, InterruptHandler_0xca, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xcb, InterruptHandler_0xcb, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xcc, InterruptHandler_0xcc, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xcd, InterruptHandler_0xcd, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xce, InterruptHandler_0xce, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xcf, InterruptHandler_0xcf, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd0, InterruptHandler_0xd0, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd1, InterruptHandler_0xd1, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd2, InterruptHandler_0xd2, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd3, InterruptHandler_0xd3, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd4, InterruptHandler_0xd4, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd5, InterruptHandler_0xd5, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd6, InterruptHandler_0xd6, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd7, InterruptHandler_0xd7, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd8, InterruptHandler_0xd8, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xd9, InterruptHandler_0xd9, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xda, InterruptHandler_0xda, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xdb, InterruptHandler_0xdb, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xdc, InterruptHandler_0xdc, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xdd, InterruptHandler_0xdd, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xde, InterruptHandler_0xde, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xdf, InterruptHandler_0xdf, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe0, InterruptHandler_0xe0, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe1, InterruptHandler_0xe1, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe2, InterruptHandler_0xe2, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe3, InterruptHandler_0xe3, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe4, InterruptHandler_0xe4, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe5, InterruptHandler_0xe5, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe6, InterruptHandler_0xe6, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe7, InterruptHandler_0xe7, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe8, InterruptHandler_0xe8, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xe9, InterruptHandler_0xe9, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xea, InterruptHandler_0xea, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xeb, InterruptHandler_0xeb, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xec, InterruptHandler_0xec, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xed, InterruptHandler_0xed, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xee, InterruptHandler_0xee, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xef, InterruptHandler_0xef, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf0, InterruptHandler_0xf0, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf1, InterruptHandler_0xf1, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf2, InterruptHandler_0xf2, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf3, InterruptHandler_0xf3, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf4, InterruptHandler_0xf4, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf5, InterruptHandler_0xf5, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf6, InterruptHandler_0xf6, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf7, InterruptHandler_0xf7, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf8, InterruptHandler_0xf8, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xf9, InterruptHandler_0xf9, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xfa, InterruptHandler_0xfa, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xfb, InterruptHandler_0xfb, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xfc, InterruptHandler_0xfc, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xfd, InterruptHandler_0xfd, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xfe, InterruptHandler_0xfe, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
SetEntry(0xff, InterruptHandler_0xff, IST0, TRAP_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
CPU::x64::lidt(&IDTr);
}
}

51
arch/amd64/cpu/idt.hpp Normal file
View File

@ -0,0 +1,51 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_IDT_H__
#define __FENNIX_KERNEL_IDT_H__
#include <types.h>
#include <cpu/x86/x64/SegmentDescriptors.hpp>
namespace InterruptDescriptorTable
{
union IDTGateDescriptor
{
InterruptGate Interrupt;
TrapGate Trap;
CallGate Call;
};
struct IDTRegister
{
uint16_t Limit;
IDTGateDescriptor *BaseAddress;
} __packed;
void SetEntry(uint8_t Index,
void (*Base)(),
InterruptStackTableType InterruptStackTable,
GateType Gate,
PrivilegeLevelType Ring,
bool Present,
uint16_t SegmentSelector);
void Init(int Core);
}
#endif // !__FENNIX_KERNEL_IDT_H__

193
arch/amd64/cpu/smp.cpp Normal file
View File

@ -0,0 +1,193 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <smp.hpp>
#include <memory.hpp>
#include <acpi.hpp>
#include <ints.hpp>
#include <assert.h>
#include <cpu.hpp>
#include <atomic>
#include "../../../kernel.h"
#include "apic.hpp"
extern "C" uint64_t _trampoline_start, _trampoline_end;
/* https://wiki.osdev.org/Memory_Map_(x86) */
enum SMPTrampolineAddress
{
PAGE_TABLE = 0x500,
START_ADDR = 0x520,
STACK = 0x570,
GDT = 0x580,
IDT = 0x590,
CORE = 0x600,
TRAMPOLINE_START = 0x2000
};
std::atomic_bool CPUEnabled = false;
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
static __aligned(PAGE_SIZE) CPUData CPUs[MAX_CPU] = {0};
SafeFunction CPUData *GetCPU(long id) { return &CPUs[id]; }
SafeFunction CPUData *GetCurrentCPU()
{
if (unlikely(!Interrupts::apic[0]))
return &CPUs[0]; /* No APIC means we are on the BSP. */
APIC::APIC *apic = (APIC::APIC *)Interrupts::apic[0];
int CoreID = 0;
if (CPUEnabled.load(std::memory_order_acquire) == true)
{
if (apic->x2APIC)
CoreID = int(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID));
else
CoreID = apic->Read(APIC::APIC_ID) >> 24;
}
if (unlikely((&CPUs[CoreID])->IsActive != true))
{
error("CPU %d is not active!", CoreID);
assert((&CPUs[0])->IsActive == true); /* We can't continue without the BSP. */
return &CPUs[0];
}
assert((&CPUs[CoreID])->Checksum == CPU_DATA_CHECKSUM); /* This should never happen. */
return &CPUs[CoreID];
}
extern "C" void StartCPU()
{
CPU::Interrupts(CPU::Disable);
int CoreID = (int)*reinterpret_cast<int *>(CORE);
CPU::InitializeFeatures(CoreID);
// Initialize GDT and IDT
Interrupts::Initialize(CoreID);
Interrupts::Enable(CoreID);
Interrupts::InitializeTimer(CoreID);
asmv("mov %0, %%rsp" ::"r"((&CPUs[CoreID])->Stack));
CPU::Interrupts(CPU::Enable);
KPrint("\e058C19CPU \e8888FF%d \e058C19is online", CoreID);
CPUEnabled.store(true, std::memory_order_release);
CPU::Halt(true);
}
namespace SMP
{
int CPUCores = 0;
void Initialize(void *_madt)
{
if (!_madt)
{
error("MADT is NULL");
return;
}
ACPI::MADT *madt = (ACPI::MADT *)_madt;
if (madt->lapic.size() < 1)
{
error("No CPUs found!");
return;
}
int Cores = madt->CPUCores + 1;
if (Config.Cores > madt->CPUCores + 1)
KPrint("More cores requested than available. Using %d cores",
madt->CPUCores + 1);
else if (Config.Cores != 0)
Cores = Config.Cores;
CPUCores = Cores;
uint64_t TrampolineLength = (uintptr_t)&_trampoline_end -
(uintptr_t)&_trampoline_start;
Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW);
/* We reserved the TRAMPOLINE_START address inside Physical class. */
Memory::Virtual().Map((void *)TRAMPOLINE_START, (void *)TRAMPOLINE_START,
TrampolineLength, Memory::PTFlag::RW);
memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength);
debug("Trampoline address: %#lx-%#lx",
TRAMPOLINE_START,
TRAMPOLINE_START + TrampolineLength);
void *CPUTmpStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
asmv("sgdt [0x580]");
asmv("sidt [0x590]");
VPOKE(uintptr_t, STACK) = (uintptr_t)CPUTmpStack + STACK_SIZE;
VPOKE(uintptr_t, PAGE_TABLE) = (uintptr_t)KernelPageTable;
VPOKE(uintptr_t, START_ADDR) = (uintptr_t)&StartCPU;
for (int i = 0; i < Cores; i++)
{
ACPI::MADT::LocalAPIC *lapic = madt->lapic[i];
APIC::APIC *apic = (APIC::APIC *)Interrupts::apic[0];
debug("Initializing CPU %d", lapic->APICId);
uint8_t APIC_ID = 0;
if (apic->x2APIC)
APIC_ID = uint8_t(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID));
else
APIC_ID = uint8_t(apic->Read(APIC::APIC_ID) >> 24);
if (APIC_ID != lapic->APICId)
{
VPOKE(int, CORE) = i;
if (!apic->x2APIC)
{
APIC::InterruptCommandRegister icr{};
icr.MT = APIC::INIT;
icr.DES = lapic->APICId;
apic->ICR(icr);
}
apic->SendInitIPI(lapic->APICId);
TimeManager->Sleep(20, Time::Units::Milliseconds);
apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
debug("Waiting for CPU %d to load...", lapic->APICId);
uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds);
while (CPUEnabled.load(std::memory_order_acquire) == false)
{
if (TimeManager->GetCounter() > Timeout)
{
error("CPU %d failed to load!", lapic->APICId);
KPrint("\eFF8C19CPU \e8888FF%d \eFF8C19failed to load!",
lapic->APICId);
break;
}
CPU::Pause();
}
trace("CPU %d loaded.", lapic->APICId);
CPUEnabled.store(false, std::memory_order_release);
}
else
KPrint("\e058C19CPU \e8888FF%d \e058C19is the BSP", lapic->APICId);
}
KernelAllocator.FreePages(CPUTmpStack, TO_PAGES(STACK_SIZE + 1));
/* We are going to unmap the page after we are done with it. */
Memory::Virtual().Unmap(0x0);
}
}

View File

@ -0,0 +1,179 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
/* This has to be the same as enum SMPTrampolineAddress. */
TRAMPOLINE_PAGE_TABLE = 0x500
TRAMPOLINE_START_ADDR = 0x520
TRAMPOLINE_STACK = 0x570
TRAMPOLINE_GDT = 0x580
TRAMPOLINE_IDT = 0x590
TRAMPOLINE_CORE = 0x600
TRAMPOLINE_START = 0x2000
.section .text, "a"
/* ========== 16-bit ========== */
.code16
.global _trampoline_start
_trampoline_start:
cli
cld
call Trampoline16
Trampoline16:
mov $0x0, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
/* Load Protected Mode GDT */
lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_START]
/* Enable Protected Mode */
mov %cr0, %eax
or $0x1, %al
mov %eax, %cr0
/* Jump to Protected Mode */
ljmp $0x8, $(Trampoline32 - _trampoline_start + TRAMPOLINE_START)
/* ========== 32-bit ========== */
.code32
Trampoline32:
mov $0x10, %bx
mov %bx, %ds
mov %bx, %es
mov %bx, %ss
/* Set a page table */
mov [TRAMPOLINE_PAGE_TABLE], %eax
mov %eax, %cr3
/* Enable PAE and PSE */
mov %cr4, %eax
or $0x20, %eax /* PAE */
or $0x80, %eax /* PSE */
mov %eax, %cr4
/* Enable Long Mode */
mov $0xC0000080, %ecx
rdmsr
or $0x100, %eax /* LME */
wrmsr
/* Enable paging */
mov %cr0, %eax
or $0x80000000, %eax /* PG */
mov %eax, %cr0
/* Load Long Mode GDT */
lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_START]
/* Jump to Long Mode */
ljmp $0x8, $(Trampoline64 - _trampoline_start + TRAMPOLINE_START)
/* ========== 64-bit ========== */
.code64
Trampoline64:
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov $0x0, %ax
mov %ax, %fs
mov %ax, %gs
/* Set custom GDT & IDT */
lgdt [TRAMPOLINE_GDT]
lidt [TRAMPOLINE_IDT]
/* Set up stack */
mov [TRAMPOLINE_STACK], %rsp
mov $0x0, %rbp
/* Reset RFLAGS */
push $0x0
popf
/* Jump to TrampolinePrepareExit */
call TrampolineExit
.extern StartCPU
TrampolineExit:
mov $StartCPU, %rax
call *%rax
.align 16
ProtectedMode_gdtr:
.word ProtectedModeGDTEnd - ProtectedModeGDTStart - 1
.long ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_START
.align 16
ProtectedModeGDTStart:
/* NULL segment */
.quad 0x0
/* Code segment */
.word 0xFFFF
.word 0x0000
.byte 0x00
.word 0xCF9A
.byte 0x00
/* Data segment */
.word 0xFFFF
.word 0x0000
.byte 0x00
.word 0xCF92
.byte 0x00
ProtectedModeGDTEnd:
nop
.align 16
LongMode_gdtr:
.word LongModeGDTEnd - LongModeGDTStart - 1
.quad LongModeGDTStart - _trampoline_start + TRAMPOLINE_START
.align 16
LongModeGDTStart:
/* NULL segment */
.quad 0x0
/* Code segment */
.word 0xFFFF
.word 0x0000
.byte 0x00
.word 0xAF98
.byte 0x00
/* Data segment */
.word 0xFFFF
.word 0x0000
.byte 0x00
.word 0xCF92
.byte 0x00
LongModeGDTEnd:
nop
.global _trampoline_end
_trampoline_end: