mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-07-02 19:09:16 +00:00
Merge remote-tracking branch 'Kernel/master'
This commit is contained in:
409
Kernel/arch/i386/cpu/apic.cpp
Normal file
409
Kernel/arch/i386/cpu/apic.cpp
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
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 <uart.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
NewLock(APICLock);
|
||||
|
||||
using namespace CPU::x32;
|
||||
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)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
return s_cst(uint32_t, rdmsr((Register >> 4) + 0x800));
|
||||
else
|
||||
return s_cst(uint32_t, rdmsr(0x30 + 0x800));
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
wrmsr((Register >> 4) + 0x800, Value);
|
||||
else
|
||||
wrmsr(MSR_X2APIC_ICR, Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
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() { this->Write(APIC_EOI, 0); }
|
||||
|
||||
void APIC::WaitForIPI()
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
do
|
||||
{
|
||||
icr.raw = this->Read(APIC_ICRLO);
|
||||
CPU::Pause();
|
||||
} while (icr.DeliveryStatus != Idle);
|
||||
}
|
||||
|
||||
void APIC::IPI(uint8_t CPU, InterruptCommandRegisterLow icr)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::SendInitIPI(uint8_t CPU)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.DeliveryMode = INIT;
|
||||
icr.Level = Assert;
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.DeliveryMode = INIT;
|
||||
icr.Level = Assert;
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::SendStartupIPI(uint8_t CPU, uint64_t StartupAddress)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.DeliveryMode = Startup;
|
||||
icr.Level = Assert;
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.DeliveryMode = Startup;
|
||||
icr.Level = Assert;
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
|
||||
{
|
||||
uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion));
|
||||
return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry;
|
||||
}
|
||||
|
||||
void APIC::RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status)
|
||||
{
|
||||
uint64_t Value = Vector;
|
||||
|
||||
int64_t IOAPICTarget = -1;
|
||||
for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(i)] != 0; i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(i)]->GSIBase <= GSI)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(i)]->GSIBase + IOGetMaxRedirect(s_cst(uint32_t, i)) > GSI)
|
||||
{
|
||||
IOAPICTarget = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IOAPICTarget == -1)
|
||||
{
|
||||
error("No ISO table found for I/O APIC");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: IOAPICRedirectEntry Entry = {.raw = 0};
|
||||
|
||||
if (Flags & ActiveHighLow)
|
||||
Value |= (1 << 13);
|
||||
|
||||
if (Flags & EdgeLevel)
|
||||
Value |= (1 << 15);
|
||||
|
||||
if (!Status)
|
||||
Value |= (1 << 16);
|
||||
|
||||
Value |= (((uintptr_t)CPU) << 56);
|
||||
uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(IOAPICTarget)]->GSIBase) * 2 + 16;
|
||||
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(IOAPICTarget)]->Address,
|
||||
IORegister, (uint32_t)Value);
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(IOAPICTarget)]->Address,
|
||||
IORegister + 1, (uint32_t)(Value >> 32));
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQ(int CPU, uint16_t IRQ, int Status)
|
||||
{
|
||||
for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->IRQSource == IRQ)
|
||||
{
|
||||
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
|
||||
i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->IRQSource,
|
||||
((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->GSI,
|
||||
CPU);
|
||||
|
||||
this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->IRQSource + 0x20,
|
||||
((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->GSI,
|
||||
((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(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(int 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.ApicBaseLo;
|
||||
uint64_t BaseHigh = BaseStruct.ApicBaseHi;
|
||||
this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u;
|
||||
trace("APIC Address: %#lx", this->APICBaseAddress);
|
||||
Memory::Virtual().Map((void *)this->APICBaseAddress, (void *)this->APICBaseAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD);
|
||||
|
||||
bool x2APICSupported = false;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
CPU::x86::AMD::CPUID0x00000001 cpuid;
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||
fixme("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
CPU::x86::Intel::CPUID0x00000001 cpuid;
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||
fixme("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
|
||||
if (x2APICSupported)
|
||||
{
|
||||
this->x2APICSupported = true;
|
||||
wrmsr(MSR_APIC_BASE, (rdmsr(MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10));
|
||||
BaseStruct.EN = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseStruct.EN = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
|
||||
this->Write(APIC_TPR, 0x0);
|
||||
// this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100
|
||||
|
||||
if (!this->x2APICSupported)
|
||||
{
|
||||
this->Write(APIC_DFR, 0xF0000000);
|
||||
this->Write(APIC_LDR, this->Read(APIC_ID));
|
||||
}
|
||||
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
|
||||
for (size_t i = 0; i < madt->nmi.size(); i++)
|
||||
{
|
||||
if (madt->nmi[std::size_t(i)]->processor != 0xFF && Core != madt->nmi[std::size_t(i)]->processor)
|
||||
return;
|
||||
|
||||
uint32_t nmi = 0x402;
|
||||
if (madt->nmi[std::size_t(i)]->flags & 2)
|
||||
nmi |= 1 << 13;
|
||||
if (madt->nmi[std::size_t(i)]->flags & 8)
|
||||
nmi |= 1 << 15;
|
||||
if (madt->nmi[std::size_t(i)]->lint == 0)
|
||||
this->Write(APIC_LINT0, nmi);
|
||||
else if (madt->nmi[std::size_t(i)]->lint == 1)
|
||||
this->Write(APIC_LINT1, nmi);
|
||||
}
|
||||
|
||||
// Setup the spurrious interrupt vector
|
||||
Spurious Spurious = {.raw = this->Read(APIC_SVR)};
|
||||
Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something?
|
||||
Spurious.Software = 1;
|
||||
this->Write(APIC_SVR, s_cst(uint32_t, Spurious.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(CPU::TrapFrame *Frame) { UNUSED(Frame); }
|
||||
|
||||
void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
LVTTimer timer = {.raw = 0};
|
||||
timer.Vector = s_cst(uint8_t, Vector);
|
||||
timer.TimerMode = 0;
|
||||
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)
|
||||
this->lapic->Write(APIC_TDCR, DivideBy128);
|
||||
else
|
||||
this->lapic->Write(APIC_TDCR, DivideBy16);
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds));
|
||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||
}
|
||||
|
||||
Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
this->lapic = apic;
|
||||
LVTTimerDivide Divider = DivideBy16;
|
||||
|
||||
trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID);
|
||||
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||
|
||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
||||
|
||||
// Mask the timer
|
||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
|
||||
|
||||
// Config for IRQ0 timer
|
||||
LVTTimer timer = {.raw = 0};
|
||||
timer.Vector = IRQ0;
|
||||
timer.Mask = Unmasked;
|
||||
timer.TimerMode = LVTTimerMode::OneShot;
|
||||
|
||||
// Initialize APIC timer
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks));
|
||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||
trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks);
|
||||
KPrint("APIC Timer: \x1b[1;32m%ld\x1b[0m ticks.", Ticks);
|
||||
}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
}
|
||||
}
|
356
Kernel/arch/i386/cpu/apic.hpp
Normal file
356
Kernel/arch/i386/cpu/apic.hpp
Normal file
@ -0,0 +1,356 @@
|
||||
/*
|
||||
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
|
||||
{
|
||||
// source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c
|
||||
APIC_ID = 0x20, // Local APIC ID
|
||||
APIC_VER = 0x30, // Local APIC Version
|
||||
APIC_TPR = 0x80, // Task Priority
|
||||
APIC_APR = 0x90, // Arbitration Priority
|
||||
APIC_PPR = 0xA0, // Processor Priority
|
||||
APIC_EOI = 0xB0, // EOI
|
||||
APIC_RRD = 0xC0, // Remote Read
|
||||
APIC_LDR = 0xD0, // Logical Destination
|
||||
APIC_DFR = 0xE0, // Destination Format
|
||||
APIC_SVR = 0xF0, // Spurious Interrupt Vector
|
||||
APIC_ISR = 0x100, // In-Service (8 registers)
|
||||
APIC_TMR = 0x180, // Trigger Mode (8 registers)
|
||||
APIC_IRR = 0x200, // Interrupt Request (8 registers)
|
||||
APIC_ESR = 0x280, // Error Status
|
||||
APIC_ICRLO = 0x300, // Interrupt Command
|
||||
APIC_ICRHI = 0x310, // Interrupt Command [63:32]
|
||||
APIC_TIMER = 0x320, // LVT Timer
|
||||
APIC_THERMAL = 0x330, // LVT Thermal Sensor
|
||||
APIC_PERF = 0x340, // LVT Performance Counter
|
||||
APIC_LINT0 = 0x350, // LVT LINT0
|
||||
APIC_LINT1 = 0x360, // LVT LINT1
|
||||
APIC_ERROR = 0x370, // LVT Error
|
||||
APIC_TICR = 0x380, // Initial Count (for Timer)
|
||||
APIC_TCCR = 0x390, // Current Count (for Timer)
|
||||
APIC_TDCR = 0x3E0, // Divide Configuration (for Timer)
|
||||
};
|
||||
|
||||
enum IOAPICRegisters
|
||||
{
|
||||
GetIOAPICVersion = 0x1
|
||||
};
|
||||
|
||||
enum IOAPICFlags
|
||||
{
|
||||
ActiveHighLow = 2,
|
||||
EdgeLevel = 8
|
||||
};
|
||||
|
||||
enum APICDeliveryMode
|
||||
{
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001, /* Reserved */
|
||||
SMI = 0b010,
|
||||
APIC_DELIVERY_MODE_RESERVED0 = 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
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 4;
|
||||
/**
|
||||
* @brief Delivery Status
|
||||
*
|
||||
* 0: Idle
|
||||
* 1: Send Pending
|
||||
*/
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 3;
|
||||
/**
|
||||
* @brief Mask
|
||||
*
|
||||
* 0: Not masked
|
||||
* 1: Masked
|
||||
*/
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Timer Mode
|
||||
*
|
||||
* 0: One-shot
|
||||
* 1: Periodic
|
||||
* 2: TSC-Deadline
|
||||
*/
|
||||
uint64_t TimerMode : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved2 : 14;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed LVTTimer;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Spurious Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Enable or disable APIC software */
|
||||
uint64_t Software : 1;
|
||||
/** @brief Focus Processor Checking */
|
||||
uint64_t FocusProcessorChecking : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved : 2;
|
||||
/** @brief Disable EOI Broadcast */
|
||||
uint64_t DisableEOIBroadcast : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 19;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed Spurious;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Delivery Mode */
|
||||
uint64_t DeliveryMode : 3;
|
||||
/** @brief Destination Mode
|
||||
*
|
||||
* 0: Physical
|
||||
* 1: Logical
|
||||
*/
|
||||
uint64_t DestinationMode : 1;
|
||||
/** @brief Delivery Status
|
||||
*
|
||||
* @note Reserved when in x2APIC mode
|
||||
*/
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 1;
|
||||
/** @brief Level
|
||||
*
|
||||
* 0: Deassert
|
||||
* 1: Assert
|
||||
*/
|
||||
uint64_t Level : 1;
|
||||
/** @brief Trigger Mode
|
||||
*
|
||||
* 0: Edge
|
||||
* 1: Level
|
||||
*/
|
||||
uint64_t TriggerMode : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 2;
|
||||
/** @brief Destination Shorthand
|
||||
*
|
||||
* 0: No shorthand
|
||||
* 1: Self
|
||||
* 2: All including self
|
||||
* 3: All excluding self
|
||||
*/
|
||||
uint64_t DestinationShorthand : 2;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved2 : 12;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed InterruptCommandRegisterLow;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t Destination : 8;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed InterruptCommandRegisterHigh;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Delivery Mode */
|
||||
uint64_t DeliveryMode : 3;
|
||||
/** @brief Destination Mode
|
||||
*
|
||||
* 0: Physical
|
||||
* 1: Logical
|
||||
*/
|
||||
uint64_t DestinationMode : 1;
|
||||
/** @brief Delivery Status */
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Interrupt Input Pin Polarity
|
||||
*
|
||||
* 0: Active High
|
||||
* 1: Active Low
|
||||
*/
|
||||
uint64_t Polarity : 1;
|
||||
/** @brief Remote IRR */
|
||||
uint64_t RemoteIRR : 1;
|
||||
/** @brief Trigger Mode
|
||||
*
|
||||
* 0: Edge
|
||||
* 1: Level
|
||||
*/
|
||||
uint64_t TriggerMode : 1;
|
||||
/** @brief Mask */
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 15;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t DestinationID : 8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint64_t Low;
|
||||
uint64_t High;
|
||||
} split;
|
||||
uint64_t raw;
|
||||
} __packed IOAPICRedirectEntry;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64_t Version : 8;
|
||||
uint64_t Reserved : 8;
|
||||
uint64_t MaximumRedirectionEntry : 8;
|
||||
uint64_t Reserved2 : 8;
|
||||
};
|
||||
uint64_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(int CPU = 0);
|
||||
void WaitForIPI();
|
||||
void IPI(uint8_t CPU, InterruptCommandRegisterLow icr);
|
||||
void SendInitIPI(uint8_t CPU);
|
||||
void SendStartupIPI(uint8_t CPU, uint64_t StartupAddress);
|
||||
uint32_t IOGetMaxRedirect(uint32_t APICID);
|
||||
void RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status);
|
||||
void RedirectIRQ(int CPU, uint16_t IRQ, int Status);
|
||||
APIC(int Core);
|
||||
~APIC();
|
||||
};
|
||||
|
||||
class Timer : public Interrupts::Handler
|
||||
{
|
||||
private:
|
||||
APIC *lapic;
|
||||
uint64_t Ticks = 0;
|
||||
void OnInterruptReceived(CPU::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__
|
262
Kernel/arch/i386/cpu/gdt.cpp
Normal file
262
Kernel/arch/i386/cpu/gdt.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
/*
|
||||
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 =
|
||||
{
|
||||
.Limit0 = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.Raw = 0x0},
|
||||
// .Limit1 = 0x0,
|
||||
.Flags = {.Raw = 0x0},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.Code =
|
||||
{
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 1,
|
||||
.S = 1,
|
||||
.DPL = 0,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.Data = {
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 0,
|
||||
.S = 1,
|
||||
.DPL = 0,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.UserData = {
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 0,
|
||||
.S = 1,
|
||||
.DPL = 3,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.UserCode = {
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 1,
|
||||
.S = 1,
|
||||
.DPL = 3,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 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];
|
||||
|
||||
nsa void Init(int Core)
|
||||
{
|
||||
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
|
||||
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
|
||||
|
||||
debug("GDT: %#lx", &gdt[Core]);
|
||||
debug("GDT KERNEL: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_KERNEL_CODE,
|
||||
GDTEntries[Core].Code.Limit0,
|
||||
GDTEntries[Core].Code.BaseLow,
|
||||
GDTEntries[Core].Code.BaseMiddle,
|
||||
GDTEntries[Core].Code.Access.Raw,
|
||||
GDTEntries[Core].Code.Flags.Reserved,
|
||||
GDTEntries[Core].Code.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].Code.BaseHigh);
|
||||
|
||||
debug("GDT KERNEL: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_KERNEL_DATA,
|
||||
GDTEntries[Core].Data.Limit0,
|
||||
GDTEntries[Core].Data.BaseLow,
|
||||
GDTEntries[Core].Data.BaseMiddle,
|
||||
GDTEntries[Core].Data.Access.Raw,
|
||||
GDTEntries[Core].Data.Flags.Reserved,
|
||||
GDTEntries[Core].Data.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].Data.BaseHigh);
|
||||
|
||||
debug("GDT USER: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_USER_CODE,
|
||||
GDTEntries[Core].UserCode.Limit0,
|
||||
GDTEntries[Core].UserCode.BaseLow,
|
||||
GDTEntries[Core].UserCode.BaseMiddle,
|
||||
GDTEntries[Core].UserCode.Access.Raw,
|
||||
GDTEntries[Core].UserCode.Flags.Reserved,
|
||||
GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].UserCode.BaseHigh);
|
||||
|
||||
debug("GDT USER: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_USER_DATA,
|
||||
GDTEntries[Core].UserData.Limit0,
|
||||
GDTEntries[Core].UserData.BaseLow,
|
||||
GDTEntries[Core].UserData.BaseMiddle,
|
||||
GDTEntries[Core].UserData.Access.Raw,
|
||||
GDTEntries[Core].UserData.Flags.Reserved,
|
||||
GDTEntries[Core].UserData.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].UserData.BaseHigh);
|
||||
|
||||
CPU::x32::lgdt(&gdt[Core]);
|
||||
|
||||
asmv("mov %%esp, %%eax\n"
|
||||
"push $16\n"
|
||||
"push %%eax\n"
|
||||
"pushf\n"
|
||||
"push $8\n"
|
||||
"push $1f\n"
|
||||
"iret\n"
|
||||
"1:\n"
|
||||
"movw $16, %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%es\n" ::
|
||||
: "memory", "eax");
|
||||
|
||||
CPUStackPointer[Core] = StackManager.Allocate(STACK_SIZE);
|
||||
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);
|
||||
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseMiddle = uint8_t((Base >> 16) & 0xFF);
|
||||
gdt[Core].Entries->TaskStateSegment.BaseHigh = uint8_t((Base >> 24) & 0xFF);
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
||||
gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
|
||||
|
||||
gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
|
||||
gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF);
|
||||
|
||||
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
|
||||
tss[Core].StackPointer[0] = (uint32_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 = StackManager.Allocate(STACK_SIZE);
|
||||
|
||||
tss[Core].InterruptStackTable[i] = (uint32_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::x32::ltr(GDT_TSS);
|
||||
debug("Global Descriptor Table initialized");
|
||||
}
|
||||
|
||||
nsa void SetKernelStack(void *Stack)
|
||||
{
|
||||
stub;
|
||||
}
|
||||
|
||||
void *GetKernelStack() { return (void *)nullptr; }
|
||||
}
|
224
Kernel/arch/i386/cpu/gdt.hpp
Normal file
224
Kernel/arch/i386/cpu/gdt.hpp
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
struct TaskStateSegmentEntry
|
||||
{
|
||||
/* LOW */
|
||||
uint16_t Limit;
|
||||
uint16_t BaseLow;
|
||||
uint8_t BaseMiddle;
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint8_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint8_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint8_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint8_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint8_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint8_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint8_t P : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Access;
|
||||
uint8_t Granularity;
|
||||
uint8_t BaseHigh;
|
||||
/* HIGH */
|
||||
uint32_t BaseUpper;
|
||||
uint32_t Reserved;
|
||||
} __packed;
|
||||
|
||||
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 GlobalDescriptorTableEntry
|
||||
{
|
||||
/** @brief Limit 0:15 */
|
||||
uint16_t Limit0 : 16;
|
||||
|
||||
/** @brief Low Base 0:15 */
|
||||
uint16_t BaseLow : 16;
|
||||
|
||||
/** @brief Middle Base 16:23 */
|
||||
uint8_t BaseMiddle : 8;
|
||||
|
||||
/** @brief Access */
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint8_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint8_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint8_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint8_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint8_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint8_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint8_t P : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Access;
|
||||
|
||||
// /** @brief Limit 16:19 */
|
||||
// uint16_t Limit1 : 4;
|
||||
|
||||
/** @brief Flags */
|
||||
union GlobalDescriptorTableFlags
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t Reserved : 4; /* FIXME: Without this, the kernel crashes. */
|
||||
/** @brief Available bit.
|
||||
* @details This bit is available for use by system software.
|
||||
*/
|
||||
uint8_t AVL : 1;
|
||||
|
||||
/** @brief Long mode.
|
||||
* @details If the long mode bit is clear, the segment is in 32-bit protected mode.
|
||||
* @details If the long mode bit is set, the segment is in 64-bit long mode.
|
||||
*/
|
||||
uint8_t L : 1;
|
||||
|
||||
/** @brief Size flag.
|
||||
* @details If the size bit is clear, the segment is in 16-bit protected mode.
|
||||
* @details If the size bit is set, the segment is in 32-bit protected mode.
|
||||
*/
|
||||
uint8_t DB : 1;
|
||||
|
||||
/** @brief Granularity bit.
|
||||
* @details If the granularity bit is clear, the segment limit is in 1 B blocks.
|
||||
* @details If the granularity bit is set, the segment limit is in 4 KiB blocks.
|
||||
*/
|
||||
uint8_t G : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Flags;
|
||||
|
||||
/** @brief High Base 24:31 */
|
||||
uint8_t BaseHigh : 8;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableEntries
|
||||
{
|
||||
GlobalDescriptorTableEntry Null;
|
||||
GlobalDescriptorTableEntry Code;
|
||||
GlobalDescriptorTableEntry Data;
|
||||
GlobalDescriptorTableEntry UserData;
|
||||
GlobalDescriptorTableEntry UserCode;
|
||||
TaskStateSegmentEntry TaskStateSegment;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableDescriptor
|
||||
{
|
||||
/** @brief GDT entries length */
|
||||
uint16_t Length;
|
||||
/** @brief GDT entries address */
|
||||
GlobalDescriptorTableEntries *Entries;
|
||||
} __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__
|
737
Kernel/arch/i386/cpu/idt.cpp
Normal file
737
Kernel/arch/i386/cpu/idt.cpp
Normal file
@ -0,0 +1,737 @@
|
||||
/*
|
||||
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)(),
|
||||
GateType Gate,
|
||||
PrivilegeLevelType Ring,
|
||||
bool Present,
|
||||
uint16_t SegmentSelector)
|
||||
{
|
||||
switch (Gate)
|
||||
{
|
||||
case INTERRUPT_GATE_32BIT:
|
||||
{
|
||||
InterruptGate gate{
|
||||
.TargetCodeSegmentOffsetLow = s_cst(uint16_t, ((uint32_t)Base & 0xFFFF)),
|
||||
.TargetCodeSegmentSelector = SegmentSelector,
|
||||
.Reserved0 = 0,
|
||||
.Type = Gate,
|
||||
.Zero = 0,
|
||||
.DescriptorPrivilegeLevel = Ring,
|
||||
.Present = Present,
|
||||
.TargetCodeSegmentOffsetHigh = s_cst(uint16_t, ((uint32_t)Base >> 16)),
|
||||
};
|
||||
Entries[Index].Interrupt = gate;
|
||||
break;
|
||||
}
|
||||
case TRAP_GATE_32BIT:
|
||||
{
|
||||
TrapGate gate{
|
||||
.TargetCodeSegmentOffsetLow = s_cst(uint16_t, ((uint32_t)Base & 0xFFFF)),
|
||||
.TargetCodeSegmentSelector = SegmentSelector,
|
||||
.Reserved0 = 0,
|
||||
.Type = Gate,
|
||||
.Zero = 0,
|
||||
.DescriptorPrivilegeLevel = Ring,
|
||||
.Present = Present,
|
||||
.TargetCodeSegmentOffsetHigh = s_cst(uint16_t, ((uint32_t)Base >> 16)),
|
||||
};
|
||||
Entries[Index].Trap = gate;
|
||||
break;
|
||||
}
|
||||
case AVAILABLE_16BIT_TSS:
|
||||
case LDT:
|
||||
case BUSY_16BIT_TSS:
|
||||
case CALL_GATE_16BIT:
|
||||
case TASK_GATE:
|
||||
case INTERRUPT_GATE_16BIT:
|
||||
case TRAP_GATE_16BIT:
|
||||
case AVAILABLE_32BIT_TSS:
|
||||
case BUSY_32BIT_TSS:
|
||||
case CALL_GATE_32BIT:
|
||||
default:
|
||||
{
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __naked __used __no_stack_protector __aligned(16) void ExceptionHandlerStub()
|
||||
{
|
||||
asm("cld\n"
|
||||
"cli\n"
|
||||
|
||||
"pusha\n"
|
||||
|
||||
"push %esp\n"
|
||||
"call ExceptionHandler\n"
|
||||
"pop %esp\n"
|
||||
|
||||
"popa\n"
|
||||
|
||||
"add $8, %esp\n"
|
||||
|
||||
"iret");
|
||||
}
|
||||
|
||||
extern "C" __naked __used __no_stack_protector __aligned(16) void InterruptHandlerStub()
|
||||
{
|
||||
asm("cld\n"
|
||||
"cli\n"
|
||||
|
||||
"pusha\n"
|
||||
|
||||
"push %esp\n"
|
||||
"call MainInterruptHandler\n"
|
||||
"pop %esp\n"
|
||||
|
||||
"popa\n"
|
||||
|
||||
"add $8, %esp\n"
|
||||
|
||||
"sti\n"
|
||||
"iret");
|
||||
}
|
||||
|
||||
#pragma region Exceptions
|
||||
|
||||
#define EXCEPTION_HANDLER(num) \
|
||||
__naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("push $0\npush $" #num "\n" \
|
||||
"jmp ExceptionHandlerStub"); \
|
||||
}
|
||||
|
||||
#define EXCEPTION_ERROR_HANDLER(num) \
|
||||
__naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("push $" #num "\n" \
|
||||
"jmp ExceptionHandlerStub"); \
|
||||
}
|
||||
|
||||
#define INTERRUPT_HANDLER(num) \
|
||||
__naked __used __no_stack_protector __aligned(16) void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("push $0\npush $" #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) /* Remap 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);
|
||||
}
|
||||
|
||||
/* ISR */
|
||||
|
||||
bool EnableISRs = true;
|
||||
// #ifdef DEBUG
|
||||
EnableISRs = !DebuggerIsAttached;
|
||||
if (!EnableISRs)
|
||||
KPrint("\x1b[34mThe debugger is attached, disabling all ISRs.");
|
||||
// #endif
|
||||
|
||||
SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1, InterruptHandler_0x1, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2, InterruptHandler_0x2, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3, InterruptHandler_0x3, TRAP_GATE_32BIT, RING3, (!DebuggerIsAttached), GDT_KERNEL_CODE); /* Do not handle breakpoints if we are debugging the kernel. */
|
||||
SetEntry(0x4, InterruptHandler_0x4, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5, InterruptHandler_0x5, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6, InterruptHandler_0x6, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7, InterruptHandler_0x7, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8, InterruptHandler_0x8, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9, InterruptHandler_0x9, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa, InterruptHandler_0xa, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb, InterruptHandler_0xb, TRAP_GATE_32BIT, RING0, (!DebuggerIsAttached), GDT_KERNEL_CODE);
|
||||
SetEntry(0xc, InterruptHandler_0xc, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd, InterruptHandler_0xd, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe, InterruptHandler_0xe, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf, InterruptHandler_0xf, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x10, InterruptHandler_0x10, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x11, InterruptHandler_0x11, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x12, InterruptHandler_0x12, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x13, InterruptHandler_0x13, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x14, InterruptHandler_0x14, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x15, InterruptHandler_0x15, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x16, InterruptHandler_0x16, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x17, InterruptHandler_0x17, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x18, InterruptHandler_0x18, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x19, InterruptHandler_0x19, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1a, InterruptHandler_0x1a, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1b, InterruptHandler_0x1b, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1c, InterruptHandler_0x1c, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1d, InterruptHandler_0x1d, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1e, InterruptHandler_0x1e, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1f, InterruptHandler_0x1f, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
|
||||
/* IRQ */
|
||||
|
||||
SetEntry(0x20, InterruptHandler_0x20, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x21, InterruptHandler_0x21, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x22, InterruptHandler_0x22, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x23, InterruptHandler_0x23, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x24, InterruptHandler_0x24, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x25, InterruptHandler_0x25, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x26, InterruptHandler_0x26, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x27, InterruptHandler_0x27, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x28, InterruptHandler_0x28, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x29, InterruptHandler_0x29, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2a, InterruptHandler_0x2a, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2b, InterruptHandler_0x2b, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2c, InterruptHandler_0x2c, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2d, InterruptHandler_0x2d, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2e, InterruptHandler_0x2e, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2f, InterruptHandler_0x2f, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
|
||||
/* Reserved by OS */
|
||||
|
||||
SetEntry(0x30, InterruptHandler_0x30, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x31, InterruptHandler_0x31, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x32, InterruptHandler_0x32, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x33, InterruptHandler_0x33, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x34, InterruptHandler_0x34, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x35, InterruptHandler_0x35, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x36, InterruptHandler_0x36, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x37, InterruptHandler_0x37, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x38, InterruptHandler_0x38, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x39, InterruptHandler_0x39, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3a, InterruptHandler_0x3a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3b, InterruptHandler_0x3b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3c, InterruptHandler_0x3c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3d, InterruptHandler_0x3d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
|
||||
/* Free */
|
||||
|
||||
SetEntry(0x3e, InterruptHandler_0x3e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3f, InterruptHandler_0x3f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x40, InterruptHandler_0x40, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x41, InterruptHandler_0x41, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x42, InterruptHandler_0x42, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x43, InterruptHandler_0x43, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x44, InterruptHandler_0x44, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x45, InterruptHandler_0x45, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x46, InterruptHandler_0x46, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x47, InterruptHandler_0x47, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x48, InterruptHandler_0x48, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x49, InterruptHandler_0x49, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4a, InterruptHandler_0x4a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4b, InterruptHandler_0x4b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4c, InterruptHandler_0x4c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4d, InterruptHandler_0x4d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4e, InterruptHandler_0x4e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4f, InterruptHandler_0x4f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x50, InterruptHandler_0x50, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x51, InterruptHandler_0x51, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x52, InterruptHandler_0x52, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x53, InterruptHandler_0x53, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x54, InterruptHandler_0x54, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x55, InterruptHandler_0x55, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x56, InterruptHandler_0x56, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x57, InterruptHandler_0x57, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x58, InterruptHandler_0x58, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x59, InterruptHandler_0x59, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5a, InterruptHandler_0x5a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5b, InterruptHandler_0x5b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5c, InterruptHandler_0x5c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5d, InterruptHandler_0x5d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5e, InterruptHandler_0x5e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5f, InterruptHandler_0x5f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x60, InterruptHandler_0x60, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x61, InterruptHandler_0x61, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x62, InterruptHandler_0x62, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x63, InterruptHandler_0x63, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x64, InterruptHandler_0x64, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x65, InterruptHandler_0x65, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x66, InterruptHandler_0x66, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x67, InterruptHandler_0x67, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x68, InterruptHandler_0x68, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x69, InterruptHandler_0x69, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6a, InterruptHandler_0x6a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6b, InterruptHandler_0x6b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6c, InterruptHandler_0x6c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6d, InterruptHandler_0x6d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6e, InterruptHandler_0x6e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6f, InterruptHandler_0x6f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x70, InterruptHandler_0x70, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x71, InterruptHandler_0x71, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x72, InterruptHandler_0x72, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x73, InterruptHandler_0x73, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x74, InterruptHandler_0x74, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x75, InterruptHandler_0x75, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x76, InterruptHandler_0x76, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x77, InterruptHandler_0x77, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x78, InterruptHandler_0x78, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x79, InterruptHandler_0x79, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7a, InterruptHandler_0x7a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7b, InterruptHandler_0x7b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7c, InterruptHandler_0x7c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7d, InterruptHandler_0x7d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7e, InterruptHandler_0x7e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7f, InterruptHandler_0x7f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x80, InterruptHandler_0x80, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x81, InterruptHandler_0x81, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x82, InterruptHandler_0x82, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x83, InterruptHandler_0x83, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x84, InterruptHandler_0x84, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x85, InterruptHandler_0x85, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x86, InterruptHandler_0x86, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x87, InterruptHandler_0x87, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x88, InterruptHandler_0x88, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x89, InterruptHandler_0x89, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8a, InterruptHandler_0x8a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8b, InterruptHandler_0x8b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8c, InterruptHandler_0x8c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8d, InterruptHandler_0x8d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8e, InterruptHandler_0x8e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8f, InterruptHandler_0x8f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x90, InterruptHandler_0x90, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x91, InterruptHandler_0x91, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x92, InterruptHandler_0x92, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x93, InterruptHandler_0x93, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x94, InterruptHandler_0x94, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x95, InterruptHandler_0x95, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x96, InterruptHandler_0x96, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x97, InterruptHandler_0x97, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x98, InterruptHandler_0x98, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x99, InterruptHandler_0x99, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9a, InterruptHandler_0x9a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9b, InterruptHandler_0x9b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9c, InterruptHandler_0x9c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9d, InterruptHandler_0x9d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9e, InterruptHandler_0x9e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9f, InterruptHandler_0x9f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa0, InterruptHandler_0xa0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa1, InterruptHandler_0xa1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa2, InterruptHandler_0xa2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa3, InterruptHandler_0xa3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa4, InterruptHandler_0xa4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa5, InterruptHandler_0xa5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa6, InterruptHandler_0xa6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa7, InterruptHandler_0xa7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa8, InterruptHandler_0xa8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa9, InterruptHandler_0xa9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xaa, InterruptHandler_0xaa, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xab, InterruptHandler_0xab, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xac, InterruptHandler_0xac, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xad, InterruptHandler_0xad, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xae, InterruptHandler_0xae, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xaf, InterruptHandler_0xaf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb0, InterruptHandler_0xb0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb1, InterruptHandler_0xb1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb2, InterruptHandler_0xb2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb3, InterruptHandler_0xb3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb4, InterruptHandler_0xb4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb5, InterruptHandler_0xb5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb6, InterruptHandler_0xb6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb7, InterruptHandler_0xb7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb8, InterruptHandler_0xb8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb9, InterruptHandler_0xb9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xba, InterruptHandler_0xba, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbb, InterruptHandler_0xbb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbc, InterruptHandler_0xbc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbd, InterruptHandler_0xbd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbe, InterruptHandler_0xbe, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbf, InterruptHandler_0xbf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc0, InterruptHandler_0xc0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc1, InterruptHandler_0xc1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc2, InterruptHandler_0xc2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc3, InterruptHandler_0xc3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc4, InterruptHandler_0xc4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc5, InterruptHandler_0xc5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc6, InterruptHandler_0xc6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc7, InterruptHandler_0xc7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc8, InterruptHandler_0xc8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc9, InterruptHandler_0xc9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xca, InterruptHandler_0xca, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcb, InterruptHandler_0xcb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcc, InterruptHandler_0xcc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcd, InterruptHandler_0xcd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xce, InterruptHandler_0xce, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcf, InterruptHandler_0xcf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd0, InterruptHandler_0xd0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd1, InterruptHandler_0xd1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd2, InterruptHandler_0xd2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd3, InterruptHandler_0xd3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd4, InterruptHandler_0xd4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd5, InterruptHandler_0xd5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd6, InterruptHandler_0xd6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd7, InterruptHandler_0xd7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd8, InterruptHandler_0xd8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd9, InterruptHandler_0xd9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xda, InterruptHandler_0xda, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdb, InterruptHandler_0xdb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdc, InterruptHandler_0xdc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdd, InterruptHandler_0xdd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xde, InterruptHandler_0xde, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdf, InterruptHandler_0xdf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe0, InterruptHandler_0xe0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe1, InterruptHandler_0xe1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe2, InterruptHandler_0xe2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe3, InterruptHandler_0xe3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe4, InterruptHandler_0xe4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe5, InterruptHandler_0xe5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe6, InterruptHandler_0xe6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe7, InterruptHandler_0xe7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe8, InterruptHandler_0xe8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe9, InterruptHandler_0xe9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xea, InterruptHandler_0xea, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xeb, InterruptHandler_0xeb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xec, InterruptHandler_0xec, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xed, InterruptHandler_0xed, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xee, InterruptHandler_0xee, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xef, InterruptHandler_0xef, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf0, InterruptHandler_0xf0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf1, InterruptHandler_0xf1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf2, InterruptHandler_0xf2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf3, InterruptHandler_0xf3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf4, InterruptHandler_0xf4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf5, InterruptHandler_0xf5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf6, InterruptHandler_0xf6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf7, InterruptHandler_0xf7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf8, InterruptHandler_0xf8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf9, InterruptHandler_0xf9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfa, InterruptHandler_0xfa, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfb, InterruptHandler_0xfb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfc, InterruptHandler_0xfc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfd, InterruptHandler_0xfd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfe, InterruptHandler_0xfe, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xff, InterruptHandler_0xff, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
CPU::x32::lidt(&IDTr);
|
||||
}
|
||||
}
|
144
Kernel/arch/i386/cpu/idt.hpp
Normal file
144
Kernel/arch/i386/cpu/idt.hpp
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
namespace InterruptDescriptorTable
|
||||
{
|
||||
/**
|
||||
* Manual: AMD Architecture Programmer's Manual Volume 2: System Programming
|
||||
* Subsection: 4.7.4 System Descriptors
|
||||
* Table: 4-5
|
||||
*
|
||||
* @note Reserved values are not listed in the table.
|
||||
*/
|
||||
enum GateType
|
||||
{
|
||||
AVAILABLE_16BIT_TSS = 0b0001,
|
||||
LDT = 0b0010,
|
||||
BUSY_16BIT_TSS = 0b0011,
|
||||
CALL_GATE_16BIT = 0b0100,
|
||||
TASK_GATE = 0b0101,
|
||||
INTERRUPT_GATE_16BIT = 0b0110,
|
||||
TRAP_GATE_16BIT = 0b0111,
|
||||
AVAILABLE_32BIT_TSS = 0b1001,
|
||||
BUSY_32BIT_TSS = 0b1011,
|
||||
CALL_GATE_32BIT = 0b1100,
|
||||
INTERRUPT_GATE_32BIT = 0b1110,
|
||||
TRAP_GATE_32BIT = 0b1111,
|
||||
};
|
||||
|
||||
enum PrivilegeLevelType
|
||||
{
|
||||
RING0 = 0b0,
|
||||
RING1 = 0b1,
|
||||
RING2 = 0b10,
|
||||
RING3 = 0b11,
|
||||
};
|
||||
|
||||
struct LDTDescriptor
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t SegmentLimitLow : 16;
|
||||
uint32_t BaseAddressLow : 16;
|
||||
/* +4 */
|
||||
uint32_t BaseAddressMiddle : 8;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t SegmentLimitHigh : 4;
|
||||
uint32_t Available : 1;
|
||||
uint32_t Zero1 : 2;
|
||||
uint32_t Granularity : 1;
|
||||
uint32_t BaseAddressHigh : 8;
|
||||
} __packed;
|
||||
|
||||
typedef LDTDescriptor TSSDescriptor;
|
||||
|
||||
struct CallGate
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t TargetCodeSegmentOffsetLow : 16;
|
||||
uint32_t TargetCodeSegmentSelector : 16;
|
||||
/* +4 */
|
||||
uint32_t ParameterCount : 4;
|
||||
uint32_t Reserved0 : 3;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t TargetCodeSegmentOffsetHigh : 16;
|
||||
} __packed;
|
||||
|
||||
struct InterruptGate
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t TargetCodeSegmentOffsetLow : 16;
|
||||
uint32_t TargetCodeSegmentSelector : 16;
|
||||
/* +4 */
|
||||
uint32_t Reserved0 : 8;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t TargetCodeSegmentOffsetHigh : 16;
|
||||
} __packed;
|
||||
|
||||
typedef InterruptGate TrapGate;
|
||||
|
||||
struct TaskGate
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t Reserved0 : 16;
|
||||
uint32_t TSSSelector : 16;
|
||||
/* +4 */
|
||||
uint32_t Reserved1 : 8;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t Reserved2 : 16;
|
||||
} __packed;
|
||||
|
||||
union IDTGateDescriptor
|
||||
{
|
||||
InterruptGate Interrupt;
|
||||
TrapGate Trap;
|
||||
CallGate Call;
|
||||
};
|
||||
|
||||
struct IDTRegister
|
||||
{
|
||||
uint16_t Limit;
|
||||
IDTGateDescriptor *BaseAddress;
|
||||
} __packed;
|
||||
|
||||
void SetEntry(uint8_t Index,
|
||||
void (*Base)(),
|
||||
GateType Gate,
|
||||
PrivilegeLevelType Ring,
|
||||
bool Present,
|
||||
uint16_t SegmentSelector);
|
||||
|
||||
void Init(int Core);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_IDT_H__
|
93
Kernel/arch/i386/cpu/smp.cpp
Normal file
93
Kernel/arch/i386/cpu/smp.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
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};
|
||||
|
||||
nsa CPUData *GetCPU(long id) { return &CPUs[id]; }
|
||||
|
||||
nsa 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::x32::rdmsr(CPU::x32::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];
|
||||
}
|
||||
|
||||
namespace SMP
|
||||
{
|
||||
int CPUCores = 0;
|
||||
|
||||
void Initialize(void *_madt)
|
||||
{
|
||||
ACPI::MADT *madt = (ACPI::MADT *)_madt;
|
||||
|
||||
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;
|
||||
|
||||
fixme("SMP::Initialize() is not implemented!");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user