Fix dodgy APIC implementation

This commit is contained in:
Curle 2022-07-10 21:57:48 +01:00
parent e09f1790a0
commit 73f6c0dade
8 changed files with 60 additions and 51 deletions

View File

@ -41,9 +41,9 @@ class Core {
size_t StackAddress = 0;
uint8_t StackData[Constants::Core::STACK_SIZE] = { 0 };
IDT CoreIDT;
GDT CoreGDT;
TSS64 CoreTSS;
IDT CoreIDT = { 0, 0 };
GDT CoreGDT = { 0, 0 };
TSS64 CoreTSS = { };
void LoadExtraRegisters(uint8_t* Data);
void SaveExtraRegisters(uint8_t* Data);
@ -58,12 +58,12 @@ class Core {
static Core* GetCore(int ID) { return Processors[ID]; }
static void PreInit();
static void Init();
private:
static Core* Processors[];
void Bootstrap();
void SetupData(size_t ID);
};

View File

@ -2,6 +2,8 @@
#include <kernel/system/acpi/madt.h>
#include <kernel/system/io.h>
#include <kernel/system/memory.h>
#include "kernel/system/core.hpp"
#include "kernel/chroma.h"
/************************
*** Team Kitty, 2021 ***
@ -51,7 +53,7 @@ void APIC::Enable() {
}
void APIC::SendEOI() {
WriteRegister(Registers::EOI, 0);
*((volatile uint32_t*) 0xfee000B0) = 0;
}
bool APIC::IsReady() {
@ -63,11 +65,14 @@ void APIC::Init() {
SerialPrintf("[ ACPI] Enabling APICs...\r\n");
SerialPrintf("[ ACPI] Memory Mapping APICs..\r\n");
for (int i = 0; i < 3; i++) {
MapVirtualPage(&KernelAddressSpace, (size_t) Address + i * PAGE_SIZE, (size_t) Address + i * PAGE_SIZE, 3);
}
Address = (void*) ACPI::MADT::instance->LocalAPICBase;
SerialPrintf("[ MADT] The APIC of this core is at 0x%p\r\n", (size_t) Address);
// TODO: Check whether the identity mapping covers this address
if (Address == nullptr) {
SerialPrintf("[ ACPI] Unable to locate APICs.\r\n");
for (;;) { }
@ -77,10 +82,6 @@ void APIC::Init() {
WriteModelSpecificRegister(0x1B, (ReadModelSpecificRegister(0x1B) | 0x800) & ~(1 << 10));
Enable();
// Disable PIC1 and 2
WritePort(0x21, 0xFF, 1);
WritePort(0xA1, 0xFF, 1);
SerialPrintf("[ ACPI] Enabling Global APIC..\r\n");
IOAPICs = ACPI::MADT::instance->GetIOApicEntries();
SerialPrintf("[ ACPI] Enabling Interrupt Source Overrides..\r\n");
@ -111,8 +112,8 @@ void APIC::InitializeCore(int Core, size_t EntryPoint) {
WriteRegister(Registers::ICR1, 0x600 | ((uint32_t) (EntryPoint / PAGE_SIZE)));
}
void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int Core, int Status) {
UNUSED(Core);
void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CoreID, int Status) {
size_t temp = Vector;
int64_t target = -1;
@ -124,7 +125,7 @@ void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int Core, i
}
if (target == -1) {
SerialPrintf("[APIC] No ISO found when setting up redirect.");
SerialPrintf("[ APIC] No ISO found when setting up redirect.\r\n");
return;
}
@ -137,6 +138,24 @@ void APIC::SetInternal(uint8_t Vector, uint32_t GSI, uint16_t Flags, int Core, i
if (!Status)
temp |= (1 << 16);
// TODO
temp |= (((size_t) Core::GetCore(CoreID)->LocalAPIC) << 56);
uint32_t IORegister = (GSI - IOAPICs[target]->GSI) * 2 + 0x10;
SerialPrintf("[ APIC] Setting interrupt %u, redirect %u, on LAPIC %u(%u) of core %u, address 0x%p, register 0x%p, data 0x%p\r\n", GSI, Vector, Core::GetCore(CoreID)->LocalAPIC, target, CoreID, IOAPICs[target]->Address, IORegister, temp);
WriteIO(IOAPICs[target]->Address, IORegister, (uint32_t) temp);
WriteIO(IOAPICs[target]->Address, IORegister + 1, (uint32_t)(temp >> 32));
}
void APIC::Set(int CPU, uint8_t IRQ, int Enabled) {
for(size_t i = 0; ISOs[i] != 0; i++) {
// We need to make sure we take into account the overrides, so check whether any IRQ is overriden
if (ISOs[i]->IRQ == IRQ) {
SetInternal(ISOs[i]->IRQ + 0x20, ISOs[i]->Interrupt, ISOs[i]->Flags, CPU, Enabled);
return;
}
}
// If there are no overrides, we can just remap it upwards
SetInternal(IRQ + 0x20, IRQ, 0, CPU, Enabled);
}

View File

@ -1,5 +1,6 @@
#include <driver/io/ps2_keyboard.h>
#include <kernel/chroma.h>
#include "driver/io/apic.h"
/************************
*** Team Kitty, 2022 ***
@ -154,6 +155,7 @@ void PS2Keyboard::InterruptHandler() {
SerialPrintf("[ KEY] %c pressed.\r\n", keys[scancode]);
state = ReadPort(0x64, 1);
setState(keystate, scancode);
KeyboardData data { keys[scancode], (char) scancode, (bool) keystate };
buffer.emplace_back(data);
}

View File

@ -77,12 +77,15 @@ extern "C" int Main(void) {
SetForegroundColor(0x00FFFFFF);
Device::APIC::driver = new Device::APIC();
Device::PS2Keyboard::driver = new Device::PS2Keyboard();
ACPI::RSDP::instance->Init(0);
ACPI::MADT::instance->Init();
Core::PreInit();
Device::APIC::driver->Init();
Device::PS2Keyboard::driver->Init();

View File

@ -40,6 +40,7 @@ MADT::IOAPICEntry** MADT::GetIOApicEntries() {
if (table->Type == MADT::Type::IOAPIC) {
MADT::IOAPICEntry* io_apic = reinterpret_cast<MADT::IOAPICEntry*>(table);
MapVirtualPage(&KernelAddressSpace, io_apic->Address, io_apic->Address, 3);
entries[count] = (MADT::IOAPICEntry*) ((size_t) io_apic);
count++;
}

View File

@ -45,7 +45,14 @@ Core::Core(size_t APIC, size_t ID) {
Ready = false;
}
void Core::PreInit() {
for (size_t i = 0; i < Constants::Core::MAX_CORES; i++) {
Processors[i] = new Core();
}
}
void Core::Init() {
using namespace ACPI;
Ready = false;
@ -78,7 +85,6 @@ void Core::Init() {
}
SerialPrintf("[ CORE] Found %d core(s).\r\n", Cores);
if (Cores > 1)
SerialPrintf("[ CORE] Bringing up other cores.\r\n");
@ -87,6 +93,7 @@ void Core::Init() {
if (Device::APIC::driver->GetCurrentCore() != LAPICs[i]->Core) {
SerialPrintf("[ CORE] Enabling core %d.\r\n", i);
delete Processors[i];
Core* c = new Core(LAPICs[i]->APIC, LAPICs[i]->Core);
Processors[i] = c;
}
@ -97,11 +104,6 @@ void Core::Bootstrap() {
// TODO
}
void Core::SetupData(size_t Core) {
UNUSED(Core);
}
void Core::StackTrace(size_t Cycles) {
StackFrame* stack;

View File

@ -1,5 +1,6 @@
#include <kernel/chroma.h>
#include <kernel/system/interrupts.h>
#include "driver/io/apic.h"
/************************
*** Team Kitty, 2020 ***
@ -71,6 +72,9 @@ void PrepareCPU() {
//SetupExtensions();
InitInterrupts();
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
WritePort(0x20, 0x20, 1);
}
void SetupInitialGDT() {

View File

@ -2,6 +2,7 @@
#include <kernel/video/draw.h>
#include <kernel/system/interrupts.h>
#include <stdbool.h>
#include "driver/io/apic.h"
/************************
*** Team Kitty, 2020 ***
@ -122,19 +123,15 @@ void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
safely tell whether we've actually got something for this IRQ. */
handler = IRQHandlers[Interrupt];
if (handler.numHandlers > 0) {
SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
//SerialPrintf("[ IRQ] IRQ %d raised!\r\n", Interrupt);
// Call the handlers
for (size_t i = 0; i < handler.numHandlers; i++)
handler.handlers[i](Frame);
}
/* The Slave PIC must be told it's been read in order to receive another 8+ IRQ. */
if (Interrupt > 7)
WritePort(0xA0, 0x20, 1);
/* In either case, we tell the Master PIC it's been read to receive any IRQ. */
WritePort(0x20, 0x20, 1);
Device::APIC::driver->SendEOI();
}
#define PIC1 0x20 /* IO base address for master PIC */
#define PIC2 0xA0 /* IO base address for slave PIC */
#define PIC1_COMMAND PIC1
@ -154,28 +151,10 @@ void IRQ_Common(INTERRUPT_FRAME* Frame, size_t Interrupt) {
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
void ClearIRQ(size_t idx) {
uint16_t port;
uint8_t value;
if(idx < 8) {
port = PIC1_DATA;
} else {
port = PIC2_DATA;
idx -= 8;
}
value = ReadPort(port, 1) & ~(1 << idx);
WritePort(port, value, 1);
}
/* However, in order to actually be able to receive IRQs, we need to remap the PICs. */
void RemapIRQControllers() {
/* 0x20 is the Master PIC,
0xA0 is the Slave PIC. */
unsigned char a1, a2;
a1 = ReadPort(PIC1_DATA, 1); // save masks
a2 = ReadPort(PIC2_DATA, 1);
WritePort(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4, 1); // starts the initialization sequence (in cascade mode)
WritePort(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4, 1);
@ -187,17 +166,17 @@ void RemapIRQControllers() {
WritePort(PIC1_DATA, ICW4_8086, 1);
WritePort(PIC2_DATA, ICW4_8086, 1);
WritePort(PIC1_DATA, a1, 1); // restore saved masks.
WritePort(PIC2_DATA, a2, 1);
WritePort(PIC1_DATA, 0xFF, 1); // restore saved masks.
WritePort(PIC2_DATA, 0xFF, 1);
ClearIRQ(1);
ClearIRQ(2);
}
/* In order to actually handle the IRQs, though, we need to tell the kernel *where* the handlers are. */
/* A simple wrapper that adds a function pointer to the IRQ array. */
size_t InstallIRQ(int IRQ, IRQHandler Handler) {
if (IRQ <= 32) {
Device::APIC::driver->Set(Core::GetCurrent()->ID, IRQ, 1);
IRQHandlerData* target = &IRQHandlers[IRQ];
if (target->numHandlers < 7) {
target->handlers[target->numHandlers] = Handler;
@ -429,7 +408,6 @@ __attribute__((interrupt)) void IRQ0Handler(INTERRUPT_FRAME* Frame) {
}
__attribute__((interrupt)) void IRQ1Handler(INTERRUPT_FRAME* Frame) {
SerialPrintf("IRQ1\r\n");
IRQ_Common(Frame, 1); // Keyboard handler
}