Kernel: Rewrite APIC and PIC more OOP friendly
x86_64 port is slowly coming together
This commit is contained in:
parent
b50bb03ed4
commit
ba53582f23
|
@ -29,24 +29,26 @@ LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
|
||||||
|
|
||||||
BUILDDIR=$(abspath build)
|
BUILDDIR=$(abspath build)
|
||||||
|
|
||||||
KERNEL_OBJS= \
|
KERNEL_OBJS= \
|
||||||
$(KERNEL_ARCH_OBJS) \
|
$(KERNEL_ARCH_OBJS) \
|
||||||
kernel/build_libc.o \
|
kernel/APIC.o \
|
||||||
kernel/CPUID.o \
|
kernel/build_libc.o \
|
||||||
kernel/font.o \
|
kernel/CPUID.o \
|
||||||
kernel/Input.o \
|
kernel/font.o \
|
||||||
kernel/kernel.o \
|
kernel/Input.o \
|
||||||
kernel/kmalloc.o \
|
kernel/InterruptController.o \
|
||||||
kernel/Panic.o \
|
kernel/kernel.o \
|
||||||
kernel/PIC.o \
|
kernel/kmalloc.o \
|
||||||
kernel/PIT.o \
|
kernel/Panic.o \
|
||||||
kernel/RTC.o \
|
kernel/PIC.o \
|
||||||
kernel/Serial.o \
|
kernel/PIT.o \
|
||||||
kernel/Shell.o \
|
kernel/RTC.o \
|
||||||
kernel/SSP.o \
|
kernel/Serial.o \
|
||||||
kernel/TTY.o \
|
kernel/Shell.o \
|
||||||
kernel/VesaTerminalDriver.o \
|
kernel/SSP.o \
|
||||||
icxxabi.o \
|
kernel/TTY.o \
|
||||||
|
kernel/VesaTerminalDriver.o \
|
||||||
|
icxxabi.o \
|
||||||
|
|
||||||
OBJS= \
|
OBJS= \
|
||||||
$(ARCHDIR)/crti.o \
|
$(ARCHDIR)/crti.o \
|
||||||
|
|
|
@ -1,440 +0,0 @@
|
||||||
#include <kernel/APIC.h>
|
|
||||||
#include <kernel/CPUID.h>
|
|
||||||
#include <kernel/IDT.h>
|
|
||||||
#include <kernel/IO.h>
|
|
||||||
#include <kernel/MMU.h>
|
|
||||||
#include <kernel/PIC.h>
|
|
||||||
#include <kernel/Serial.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define APIC_DEBUG_PRINT 0
|
|
||||||
|
|
||||||
#define IA32_APIC_BASE 0x1B
|
|
||||||
#define IA32_APIC_BASE_ENABLE (1 << 11)
|
|
||||||
|
|
||||||
namespace APIC
|
|
||||||
{
|
|
||||||
|
|
||||||
static bool s_using_fallback_pic = false;
|
|
||||||
|
|
||||||
static uint8_t s_processor_ids[0x100] { };
|
|
||||||
static uint8_t s_lapic_ids[0x100] { };
|
|
||||||
static uint8_t s_lapic_count = 0;
|
|
||||||
|
|
||||||
static uint32_t s_local_apic = 0;
|
|
||||||
static uint32_t s_io_apic = 0;
|
|
||||||
|
|
||||||
static uint8_t s_overrides[0x100];
|
|
||||||
|
|
||||||
struct RSDPDescriptor
|
|
||||||
{
|
|
||||||
char signature[8];
|
|
||||||
uint8_t checksum;
|
|
||||||
char OEMID[6];
|
|
||||||
uint8_t revision;
|
|
||||||
uint32_t rsdt_address;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct RSDPDescriptor20
|
|
||||||
{
|
|
||||||
RSDPDescriptor firstPart;
|
|
||||||
uint32_t length;
|
|
||||||
uint64_t xsdt_address;
|
|
||||||
uint8_t extended_checksum;
|
|
||||||
uint8_t reserved[3];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct ACPISDTHeader
|
|
||||||
{
|
|
||||||
char signature[4];
|
|
||||||
uint32_t length;
|
|
||||||
uint8_t eevision;
|
|
||||||
uint8_t checksum;
|
|
||||||
char OEMID[6];
|
|
||||||
char OEM_table_id[8];
|
|
||||||
uint32_t OEM_revision;
|
|
||||||
uint32_t creator_id;
|
|
||||||
uint32_t creator_revision;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct RSDT
|
|
||||||
{
|
|
||||||
ACPISDTHeader header;
|
|
||||||
uint32_t sdt_pointer[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct XSDT
|
|
||||||
{
|
|
||||||
ACPISDTHeader header;
|
|
||||||
uint64_t sdt_pointer[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MADT
|
|
||||||
{
|
|
||||||
ACPISDTHeader header;
|
|
||||||
uint32_t local_apic;
|
|
||||||
uint32_t flags;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct MADTEntry
|
|
||||||
{
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t length;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t acpi_processor_id;
|
|
||||||
uint8_t apic_id;
|
|
||||||
uint32_t flags;
|
|
||||||
} __attribute__((packed)) entry0;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t ioapic_id;
|
|
||||||
uint8_t reserved;
|
|
||||||
uint32_t ioapic_address;
|
|
||||||
uint32_t gsi_base;
|
|
||||||
} __attribute__((packed)) entry1;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t bus_source;
|
|
||||||
uint8_t irq_source;
|
|
||||||
uint32_t gsi;
|
|
||||||
uint16_t flags;
|
|
||||||
} __attribute__((packed)) entry2;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t nmi_source;
|
|
||||||
uint8_t reserved;
|
|
||||||
uint16_t flags;
|
|
||||||
uint32_t gsi;
|
|
||||||
} __attribute__((packed)) entry3;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint8_t acpi_processor_id;
|
|
||||||
uint16_t flags;
|
|
||||||
uint8_t lint;
|
|
||||||
} __attribute__((packed)) entry4;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint16_t reserved;
|
|
||||||
uint64_t address;
|
|
||||||
} __attribute__((packed)) entry5;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint16_t reserved;
|
|
||||||
uint32_t local_x2acpi_id;
|
|
||||||
uint32_t flags;
|
|
||||||
uint32_t acpi_id;
|
|
||||||
} __attribute__((packed)) entry9;
|
|
||||||
};
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
union RedirectionEntry
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint64_t vector : 8;
|
|
||||||
uint64_t delivery_mode : 3;
|
|
||||||
uint64_t destination_mode : 1;
|
|
||||||
uint64_t delivery_status : 1;
|
|
||||||
uint64_t pin_polarity : 1;
|
|
||||||
uint64_t remote_irr : 1;
|
|
||||||
uint64_t trigger_mode : 1;
|
|
||||||
uint64_t mask : 1;
|
|
||||||
uint64_t reserved : 39;
|
|
||||||
uint64_t destination : 8;
|
|
||||||
};
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32_t lo_dword;
|
|
||||||
uint32_t hi_dword;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static uint32_t ReadLocalAPIC(uint32_t offset);
|
|
||||||
static void WriteLocalAPIC(uint32_t offset, uint32_t value);
|
|
||||||
static uint32_t ReadIOAPIC(uint8_t reg);
|
|
||||||
static void WriteIOAPIC(uint8_t reg, uint32_t value);
|
|
||||||
static void SetMSR(uint32_t msr, uint32_t lo, uint32_t hi);
|
|
||||||
|
|
||||||
|
|
||||||
static bool IsRSDP(RSDPDescriptor* rsdp)
|
|
||||||
{
|
|
||||||
if (memcmp(rsdp->signature, "RSD PTR ", 8) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
{
|
|
||||||
uint8_t checksum = 0;
|
|
||||||
for (uint32_t i = 0; i < sizeof(RSDPDescriptor); i++)
|
|
||||||
checksum += ((uint8_t*)rsdp)[i];
|
|
||||||
if (checksum != 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rsdp->revision == 2)
|
|
||||||
{
|
|
||||||
RSDPDescriptor20* rsdp20 = (RSDPDescriptor20*)rsdp;
|
|
||||||
uint8_t checksum = 0;
|
|
||||||
for (uint32_t i = 0; i < sizeof(RSDPDescriptor20); i++)
|
|
||||||
checksum += ((uint8_t*)rsdp20)[i];
|
|
||||||
if (checksum != 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static RSDPDescriptor* LocateRSDP()
|
|
||||||
{
|
|
||||||
// Look in main BIOS area below 1 MB
|
|
||||||
for (uint32_t addr = 0x000E0000; addr < 0x000FFFFF; addr += 16)
|
|
||||||
if (IsRSDP((RSDPDescriptor*)addr))
|
|
||||||
return (RSDPDescriptor*)addr;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsValidACPISDTHeader(ACPISDTHeader* header)
|
|
||||||
{
|
|
||||||
uint8_t sum = 0;
|
|
||||||
for (uint32_t i = 0; i < header->length; i++)
|
|
||||||
sum += ((uint8_t*)header)[i];
|
|
||||||
return sum == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ParseMADT(RSDPDescriptor* rsdp)
|
|
||||||
{
|
|
||||||
RSDT* const root = (RSDT*)(rsdp->revision == 2 ? ((RSDPDescriptor20*)rsdp)->xsdt_address : rsdp->rsdt_address);
|
|
||||||
MMU::Get().AllocatePage((uintptr_t)root);
|
|
||||||
uint32_t sdt_entry_count = (root->header.length - sizeof(root->header)) / (rsdp->revision == 2 ? 8 : 4);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sdt_entry_count; i++)
|
|
||||||
{
|
|
||||||
ACPISDTHeader* header = (ACPISDTHeader*)(rsdp->revision == 2 ? ((uint64_t*)root->sdt_pointer)[i] : root->sdt_pointer[i]);
|
|
||||||
if (!IsValidACPISDTHeader(header))
|
|
||||||
continue;
|
|
||||||
if (memcmp(header->signature, "APIC", 4) == 0)
|
|
||||||
{
|
|
||||||
MADT* madt = (MADT*)header;
|
|
||||||
s_local_apic = madt->local_apic;
|
|
||||||
uint32_t entry_addr = (uint32_t)madt + sizeof(MADT);
|
|
||||||
while (entry_addr < (uint32_t)madt + madt->header.length)
|
|
||||||
{
|
|
||||||
MADTEntry* entry = (MADTEntry*)entry_addr;
|
|
||||||
switch (entry->type)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
s_processor_ids[s_lapic_count] = entry->entry0.acpi_processor_id;
|
|
||||||
s_lapic_ids[s_lapic_count] = entry->entry0.apic_id;
|
|
||||||
s_lapic_count++;
|
|
||||||
#if APIC_DEBUG_PRINT >= 2
|
|
||||||
dprintln("Entry0, processor id {}, apic id {}, flags 0b{32b}",
|
|
||||||
entry->entry0.acpi_processor_id,
|
|
||||||
entry->entry0.apic_id,
|
|
||||||
entry->entry0.flags
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (s_io_apic == 0)
|
|
||||||
s_io_apic = entry->entry1.ioapic_address;
|
|
||||||
#if APIC_DEBUG_PRINT
|
|
||||||
dprintln("Entry1, io apic id {}, io apic address 0x{4H}, gsi base {}",
|
|
||||||
entry->entry1.ioapic_id,
|
|
||||||
entry->entry1.ioapic_address,
|
|
||||||
entry->entry1.gsi_base
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
s_overrides[entry->entry2.irq_source] = entry->entry2.gsi;
|
|
||||||
#if APIC_DEBUG_PRINT
|
|
||||||
dprintln("Entry2, bus source {}, irq source {}, gsi {}, flags 0b{16b}",
|
|
||||||
entry->entry2.bus_source,
|
|
||||||
entry->entry2.irq_source,
|
|
||||||
entry->entry2.gsi,
|
|
||||||
entry->entry2.flags
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
#if APIC_DEBUG_PRINT
|
|
||||||
dprintln("Entry3, nmi source {}, flags 0b{16b}, gsi {}",
|
|
||||||
entry->entry3.nmi_source,
|
|
||||||
entry->entry3.flags,
|
|
||||||
entry->entry3.gsi
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
#if APIC_DEBUG_PRINT
|
|
||||||
dprintln("Entry4, acpi processor id 0x{2H}, flags 0b{16b}, lint{}",
|
|
||||||
entry->entry4.acpi_processor_id,
|
|
||||||
entry->entry4.flags,
|
|
||||||
entry->entry4.lint
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
s_local_apic = entry->entry5.address;
|
|
||||||
#if APIC_DEBUG_PRINT
|
|
||||||
dprintln("Entry5, address 0x{4H}",
|
|
||||||
entry->entry5.address
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
#if APIC_DEBUG_PRINT
|
|
||||||
dprintln("Entry9, x2 acpi id {}, flags 0b{32b}, acpi id {}",
|
|
||||||
entry->entry9.local_x2acpi_id,
|
|
||||||
entry->entry9.flags,
|
|
||||||
entry->entry9.acpi_id
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
entry_addr += entry->length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MMU::Get().UnAllocatePage((uintptr_t)root);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t ReadLocalAPIC(uint32_t offset)
|
|
||||||
{
|
|
||||||
return *(uint32_t*)(s_local_apic + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WriteLocalAPIC(uint32_t offset, uint32_t value)
|
|
||||||
{
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
|
||||||
*(uint32_t*)(s_local_apic + offset) = value;
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t ReadIOAPIC(uint8_t reg)
|
|
||||||
{
|
|
||||||
volatile uint32_t* ioapic = (volatile uint32_t*)s_io_apic;
|
|
||||||
ioapic[0] = reg;
|
|
||||||
return ioapic[4];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WriteIOAPIC(uint8_t reg, uint32_t value)
|
|
||||||
{
|
|
||||||
volatile uint32_t* ioapic = (volatile uint32_t*)s_io_apic;
|
|
||||||
ioapic[0] = reg;
|
|
||||||
ioapic[4] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SetMSR(uint32_t msr, uint32_t lo, uint32_t hi)
|
|
||||||
{
|
|
||||||
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool InitializeAPIC()
|
|
||||||
{
|
|
||||||
uint32_t ecx, edx;
|
|
||||||
CPUID::GetFeatures(ecx, edx);
|
|
||||||
if (!(edx & CPUID::Features::EDX_APIC))
|
|
||||||
{
|
|
||||||
dprintln("Local APIC not available");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!(edx & CPUID::Features::EDX_MSR))
|
|
||||||
{
|
|
||||||
dprintln("MSR not available");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RSDPDescriptor* rsdp = LocateRSDP();
|
|
||||||
if (rsdp == nullptr)
|
|
||||||
{
|
|
||||||
dprintln("Could not locate RSDP");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseMADT(rsdp);
|
|
||||||
|
|
||||||
if (s_local_apic == 0 || s_io_apic == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MMU::Get().AllocatePage(s_io_apic);
|
|
||||||
MMU::Get().AllocatePage(s_local_apic);
|
|
||||||
|
|
||||||
// Enable Local APIC
|
|
||||||
SetMSR(IA32_APIC_BASE, (s_local_apic & 0xFFFFF000) | IA32_APIC_BASE_ENABLE, 0);
|
|
||||||
|
|
||||||
uint32_t sivr = ReadLocalAPIC(0xF0);
|
|
||||||
WriteLocalAPIC(0xF0, sivr | 0x1FF);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Initialize(bool force_pic)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0x00; i <= 0xFF; i++)
|
|
||||||
s_overrides[i] = i;
|
|
||||||
|
|
||||||
PIC::MaskAll();
|
|
||||||
PIC::Remap();
|
|
||||||
|
|
||||||
if (force_pic)
|
|
||||||
{
|
|
||||||
dprintln("Using PIC instead of APIC");
|
|
||||||
s_using_fallback_pic = true;
|
|
||||||
}
|
|
||||||
else if (!InitializeAPIC())
|
|
||||||
{
|
|
||||||
dprintln("Could not initialize APIC. Using PIC as fallback");
|
|
||||||
s_using_fallback_pic = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EOI(uint8_t irq)
|
|
||||||
{
|
|
||||||
if (s_using_fallback_pic)
|
|
||||||
return PIC::EOI(irq);
|
|
||||||
WriteLocalAPIC(0xB0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetISR(uint32_t out[8])
|
|
||||||
{
|
|
||||||
if (s_using_fallback_pic)
|
|
||||||
{
|
|
||||||
memset(out, 0, sizeof(uint32_t) * 8);
|
|
||||||
uint32_t addr = (uint32_t)out + IRQ_VECTOR_BASE / 8;
|
|
||||||
*(uint16_t*)addr = PIC::GetISR();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 8; i++)
|
|
||||||
out[i] = ReadLocalAPIC(0x100 + i * 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnableIRQ(uint8_t irq)
|
|
||||||
{
|
|
||||||
if (s_using_fallback_pic)
|
|
||||||
return PIC::Unmask(irq);
|
|
||||||
|
|
||||||
uint32_t gsi = s_overrides[irq];
|
|
||||||
|
|
||||||
RedirectionEntry redir;
|
|
||||||
redir.lo_dword = ReadIOAPIC(0x10 + gsi * 2);
|
|
||||||
redir.hi_dword = ReadIOAPIC(0x10 + gsi * 2 + 1);
|
|
||||||
|
|
||||||
redir.vector = IRQ_VECTOR_BASE + irq;
|
|
||||||
redir.mask = 0;
|
|
||||||
redir.destination = s_lapic_ids[0];
|
|
||||||
|
|
||||||
WriteIOAPIC(0x10 + gsi * 2, redir.lo_dword);
|
|
||||||
WriteIOAPIC(0x10 + gsi * 2 + 1, redir.hi_dword);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <kernel/APIC.h>
|
#include <BAN/Errors.h>
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/kmalloc.h>
|
#include <kernel/kmalloc.h>
|
||||||
#include <kernel/Panic.h>
|
#include <kernel/Panic.h>
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ namespace IDT
|
||||||
} __attribute((packed));
|
} __attribute((packed));
|
||||||
|
|
||||||
static IDTR s_idtr;
|
static IDTR s_idtr;
|
||||||
static GateDescriptor* s_idt;
|
static GateDescriptor* s_idt = nullptr;
|
||||||
|
|
||||||
static void (**s_irq_handlers)();
|
static void (**s_irq_handlers)();
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ namespace IDT
|
||||||
extern "C" void handle_irq()
|
extern "C" void handle_irq()
|
||||||
{
|
{
|
||||||
uint32_t isr[8];
|
uint32_t isr[8];
|
||||||
APIC::GetISR(isr);
|
InterruptController::Get().GetISR(isr);
|
||||||
|
|
||||||
uint8_t irq = 0;
|
uint8_t irq = 0;
|
||||||
for (uint8_t i = 0; i < 8; i++)
|
for (uint8_t i = 0; i < 8; i++)
|
||||||
|
@ -137,7 +138,7 @@ namespace IDT
|
||||||
else
|
else
|
||||||
Kernel::Panic("no handler for irq 0x{2H}\n", irq);
|
Kernel::Panic("no handler for irq 0x{2H}\n", irq);
|
||||||
|
|
||||||
APIC::EOI(irq);
|
InterruptController::Get().EOI(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void handle_irq_common();
|
extern "C" void handle_irq_common();
|
||||||
|
@ -192,7 +193,7 @@ namespace IDT
|
||||||
s_idtr.offset = s_idt;
|
s_idtr.offset = s_idt;
|
||||||
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
|
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
|
||||||
|
|
||||||
for (uint8_t i = 0xFF; i > IRQ_VECTOR_BASE; i--)
|
for (uint8_t i = 0x00; i <= 0xFF - IRQ_VECTOR_BASE; i++)
|
||||||
register_irq_handler(i, nullptr);
|
register_irq_handler(i, nullptr);
|
||||||
|
|
||||||
REGISTER_HANDLER(0x00);
|
REGISTER_HANDLER(0x00);
|
||||||
|
|
|
@ -4,7 +4,6 @@ KERNEL_ARCH_LDFLAGS=
|
||||||
KERNEL_ARCH_LIBS=
|
KERNEL_ARCH_LIBS=
|
||||||
|
|
||||||
KERNEL_ARCH_OBJS= \
|
KERNEL_ARCH_OBJS= \
|
||||||
$(ARCHDIR)/APIC.o \
|
|
||||||
$(ARCHDIR)/boot.o \
|
$(ARCHDIR)/boot.o \
|
||||||
$(ARCHDIR)/IDT.o \
|
$(ARCHDIR)/IDT.o \
|
||||||
$(ARCHDIR)/MMU.o \
|
$(ARCHDIR)/MMU.o \
|
||||||
|
|
|
@ -1,13 +1,50 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
|
|
||||||
namespace APIC
|
class APIC final : public InterruptController
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
virtual void EOI(uint8_t) override;
|
||||||
|
virtual void EnableIrq(uint8_t) override;
|
||||||
|
virtual void GetISR(uint32_t[8]) override;
|
||||||
|
|
||||||
void Initialize(bool force_pic = false);
|
private:
|
||||||
void EOI(uint8_t irq);
|
uint32_t ReadFromLocalAPIC(ptrdiff_t);
|
||||||
void GetISR(uint32_t[8]);
|
void WriteToLocalAPIC(ptrdiff_t, uint32_t);
|
||||||
void EnableIRQ(uint8_t irq);
|
|
||||||
|
|
||||||
}
|
private:
|
||||||
|
static APIC* Create();
|
||||||
|
friend class InterruptController;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Processor
|
||||||
|
{
|
||||||
|
enum Flags : uint8_t
|
||||||
|
{
|
||||||
|
Enabled = 1,
|
||||||
|
OnlineCapable = 2,
|
||||||
|
};
|
||||||
|
uint8_t processor_id;
|
||||||
|
uint8_t apic_id;
|
||||||
|
uint8_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IOAPIC
|
||||||
|
{
|
||||||
|
uint8_t id;
|
||||||
|
uintptr_t address;
|
||||||
|
uint32_t gsi_base;
|
||||||
|
uint8_t max_redirs;
|
||||||
|
|
||||||
|
uint32_t Read(uint8_t offset);
|
||||||
|
void Write(uint8_t offset, uint32_t data);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAN::Vector<Processor> m_processors;
|
||||||
|
uintptr_t m_local_apic = 0;
|
||||||
|
BAN::Vector<IOAPIC> m_io_apics;
|
||||||
|
uint8_t m_irq_overrides[0x100] {};
|
||||||
|
};
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class InterruptController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~InterruptController() {}
|
||||||
|
|
||||||
|
virtual void EOI(uint8_t) = 0;
|
||||||
|
virtual void EnableIrq(uint8_t) = 0;
|
||||||
|
virtual void GetISR(uint32_t[8]) = 0;
|
||||||
|
|
||||||
|
static void Initialize(bool force_pic);
|
||||||
|
static InterruptController& Get();
|
||||||
|
};
|
|
@ -1,16 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <kernel/InterruptController.h>
|
||||||
|
|
||||||
namespace PIC
|
class PIC final : public InterruptController
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
virtual void EOI(uint8_t) override;
|
||||||
|
virtual void EnableIrq(uint8_t) override;
|
||||||
|
virtual void GetISR(uint32_t[8]) override;
|
||||||
|
|
||||||
void Remap();
|
static void Remap();
|
||||||
void MaskAll();
|
static void MaskAll();
|
||||||
void EOI(uint8_t);
|
|
||||||
void Unmask(uint8_t);
|
|
||||||
void Mask(uint8_t);
|
|
||||||
|
|
||||||
uint16_t GetISR();
|
private:
|
||||||
|
static PIC* Create();
|
||||||
}
|
friend class InterruptController;
|
||||||
|
};
|
|
@ -0,0 +1,365 @@
|
||||||
|
#include <BAN/ScopeGuard.h>
|
||||||
|
#include <kernel/APIC.h>
|
||||||
|
#include <kernel/CPUID.h>
|
||||||
|
#include <kernel/IDT.h>
|
||||||
|
#include <kernel/IO.h>
|
||||||
|
#include <kernel/MMU.h>
|
||||||
|
#include <kernel/Serial.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define LAPIC_EIO_REG 0xB0
|
||||||
|
#define LAPIC_SIV_REG 0xF0
|
||||||
|
#define LAPIC_IS_REG 0x100
|
||||||
|
|
||||||
|
#define IOAPIC_MAX_REDIRS 0x01
|
||||||
|
#define IOAPIC_REDIRS 0x10
|
||||||
|
|
||||||
|
|
||||||
|
#define PIC1 0x20
|
||||||
|
#define PIC2 0xA0
|
||||||
|
#define PIC1_COMMAND PIC1
|
||||||
|
#define PIC1_DATA (PIC1+1)
|
||||||
|
#define PIC2_COMMAND PIC2
|
||||||
|
#define PIC2_DATA (PIC2+1)
|
||||||
|
#define ICW1_ICW4 0x01
|
||||||
|
#define ICW1_INIT 0x10
|
||||||
|
#define ICW4_8086 0x01
|
||||||
|
|
||||||
|
|
||||||
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt-format
|
||||||
|
|
||||||
|
struct RSDPDescriptor
|
||||||
|
{
|
||||||
|
char signature[8];
|
||||||
|
uint8_t checksum;
|
||||||
|
char OEMID[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_address;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct RSDPDescriptor20
|
||||||
|
{
|
||||||
|
RSDPDescriptor first_part;
|
||||||
|
uint32_t length;
|
||||||
|
uint64_t xsdt_address;
|
||||||
|
uint8_t extended_checksum;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct ACPISDTHeader
|
||||||
|
{
|
||||||
|
char signature[4];
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t checksum;
|
||||||
|
char OEMID[6];
|
||||||
|
char OEM_table_id[8];
|
||||||
|
uint32_t OEM_revision;
|
||||||
|
uint32_t creator_id;
|
||||||
|
uint32_t creator_revision;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct RSDT
|
||||||
|
{
|
||||||
|
ACPISDTHeader header;
|
||||||
|
uint32_t sdt_pointer[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct XSDT
|
||||||
|
{
|
||||||
|
ACPISDTHeader header;
|
||||||
|
uint64_t sdt_pointer[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MADT
|
||||||
|
{
|
||||||
|
ACPISDTHeader header;
|
||||||
|
uint32_t local_apic;
|
||||||
|
uint32_t flags;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct MADTEntry
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t length;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t acpi_processor_id;
|
||||||
|
uint8_t apic_id;
|
||||||
|
uint32_t flags;
|
||||||
|
} __attribute__((packed)) entry0;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t ioapic_id;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint32_t ioapic_address;
|
||||||
|
uint32_t gsi_base;
|
||||||
|
} __attribute__((packed)) entry1;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t bus_source;
|
||||||
|
uint8_t irq_source;
|
||||||
|
uint32_t gsi;
|
||||||
|
uint16_t flags;
|
||||||
|
} __attribute__((packed)) entry2;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t reserved;
|
||||||
|
uint64_t address;
|
||||||
|
} __attribute__((packed)) entry5;
|
||||||
|
};
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
union RedirectionEntry
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint64_t vector : 8;
|
||||||
|
uint64_t delivery_mode : 3;
|
||||||
|
uint64_t destination_mode : 1;
|
||||||
|
uint64_t delivery_status : 1;
|
||||||
|
uint64_t pin_polarity : 1;
|
||||||
|
uint64_t remote_irr : 1;
|
||||||
|
uint64_t trigger_mode : 1;
|
||||||
|
uint64_t mask : 1;
|
||||||
|
uint64_t reserved : 39;
|
||||||
|
uint64_t destination : 8;
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t lo_dword;
|
||||||
|
uint32_t hi_dword;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool IsRSDP(const RSDPDescriptor* rsdp)
|
||||||
|
{
|
||||||
|
if (memcmp(rsdp->signature, "RSD PTR ", 8) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
for (uint32_t i = 0; i < sizeof(RSDPDescriptor); i++)
|
||||||
|
checksum += ((uint8_t*)rsdp)[i];
|
||||||
|
if (checksum != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsdp->revision == 2)
|
||||||
|
{
|
||||||
|
RSDPDescriptor20* rsdp20 = (RSDPDescriptor20*)rsdp;
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
for (uint32_t i = 0; i < sizeof(RSDPDescriptor20); i++)
|
||||||
|
checksum += ((uint8_t*)rsdp20)[i];
|
||||||
|
if (checksum != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RSDPDescriptor* LocateRSDP()
|
||||||
|
{
|
||||||
|
// Look in main BIOS area below 1 MB
|
||||||
|
for (uintptr_t addr = 0x000E0000; addr < 0x000FFFFF; addr += 16)
|
||||||
|
if (IsRSDP((RSDPDescriptor*)addr))
|
||||||
|
return (RSDPDescriptor*)addr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsValidACPISDTHeader(ACPISDTHeader* header)
|
||||||
|
{
|
||||||
|
uint8_t sum = 0;
|
||||||
|
for (uint32_t i = 0; i < header->length; i++)
|
||||||
|
sum += ((uint8_t*)header)[i];
|
||||||
|
return sum == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MADT* LocateMADT(const RSDPDescriptor* rsdp)
|
||||||
|
{
|
||||||
|
uintptr_t root_addr = 0;
|
||||||
|
uint32_t entry_count = 0;
|
||||||
|
if (rsdp->revision == 2)
|
||||||
|
{
|
||||||
|
const XSDT* root = (const XSDT*)((RSDPDescriptor20*)rsdp)->xsdt_address;
|
||||||
|
MMU::Get().AllocatePage((uintptr_t)root);
|
||||||
|
entry_count = (root->header.length - sizeof(root->header)) / sizeof(*root->sdt_pointer);
|
||||||
|
root_addr = (uintptr_t)root;
|
||||||
|
dprintln("XSDT");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const RSDT* root = (const RSDT*)(uintptr_t)rsdp->rsdt_address;
|
||||||
|
MMU::Get().AllocatePage((uintptr_t)root);
|
||||||
|
entry_count = (root->header.length - sizeof(root->header)) / sizeof(*root->sdt_pointer);
|
||||||
|
root_addr = (uintptr_t)root;
|
||||||
|
dprintln("RSDT");
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ScopeGuard guard([root_addr]() { MMU::Get().UnAllocatePage(root_addr); });
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < entry_count; i++)
|
||||||
|
{
|
||||||
|
ACPISDTHeader* header = nullptr;
|
||||||
|
if (rsdp->revision == 2)
|
||||||
|
header = (ACPISDTHeader*)((const XSDT*)root_addr)->sdt_pointer[i];
|
||||||
|
else
|
||||||
|
header = (ACPISDTHeader*)(uintptr_t)((const RSDT*)root_addr)->sdt_pointer[i];
|
||||||
|
if (memcmp(header->signature, "APIC", 4) == 0 && IsValidACPISDTHeader(header))
|
||||||
|
return (MADT*)header;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
APIC* APIC::Create()
|
||||||
|
{
|
||||||
|
uint32_t ecx, edx;
|
||||||
|
CPUID::GetFeatures(ecx, edx);
|
||||||
|
if (!(edx & CPUID::Features::EDX_APIC))
|
||||||
|
{
|
||||||
|
dprintln("Local APIC is not available");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RSDPDescriptor* rsdp = LocateRSDP();
|
||||||
|
if (rsdp == nullptr)
|
||||||
|
{
|
||||||
|
dprintln("Could not locate RSDP");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MADT* madt = LocateMADT(rsdp);
|
||||||
|
if (madt == nullptr)
|
||||||
|
{
|
||||||
|
dprintln("Could not find MADT in RSDP");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMU::Get().AllocatePage((uintptr_t)madt);
|
||||||
|
|
||||||
|
APIC* apic = new APIC;
|
||||||
|
apic->m_local_apic = madt->local_apic;
|
||||||
|
for (uint32_t i = 0x00; i <= 0xFF; i++)
|
||||||
|
apic->m_irq_overrides[i] = i;
|
||||||
|
|
||||||
|
uintptr_t madt_entry_addr = (uintptr_t)madt + sizeof(MADT);
|
||||||
|
while (madt_entry_addr < (uintptr_t)madt + madt->header.length)
|
||||||
|
{
|
||||||
|
MADTEntry* entry = (MADTEntry*)madt_entry_addr;
|
||||||
|
switch (entry->type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Processor processor;
|
||||||
|
processor.processor_id = entry->entry0.acpi_processor_id;
|
||||||
|
processor.apic_id = entry->entry0.apic_id;
|
||||||
|
processor.flags = entry->entry0.flags & 0x03;
|
||||||
|
MUST(apic->m_processors.PushBack(processor));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
IOAPIC ioapic;
|
||||||
|
ioapic.id = entry->entry1.ioapic_id;
|
||||||
|
ioapic.address = entry->entry1.ioapic_address;
|
||||||
|
ioapic.gsi_base = entry->entry1.gsi_base;
|
||||||
|
ioapic.max_redirs = 0;
|
||||||
|
MUST(apic->m_io_apics.PushBack(ioapic));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
apic->m_irq_overrides[entry->entry2.irq_source] = entry->entry2.gsi;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
apic->m_local_apic = entry->entry5.address;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintln("Unhandled madt entry, type {}", entry->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
madt_entry_addr += entry->length;
|
||||||
|
}
|
||||||
|
MMU::Get().UnAllocatePage((uintptr_t)madt);
|
||||||
|
|
||||||
|
if (apic->m_local_apic == 0 || apic->m_io_apics.Empty())
|
||||||
|
{
|
||||||
|
dprintln("MADT did not provide necessary information");
|
||||||
|
delete apic;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMU::Get().AllocatePage(apic->m_local_apic);
|
||||||
|
for (auto& io_apic : apic->m_io_apics)
|
||||||
|
{
|
||||||
|
MMU::Get().AllocatePage(io_apic.address);
|
||||||
|
io_apic.max_redirs = io_apic.Read(IOAPIC_MAX_REDIRS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask all interrupts
|
||||||
|
uint32_t sivr = apic->ReadFromLocalAPIC(LAPIC_SIV_REG);
|
||||||
|
apic->WriteToLocalAPIC(LAPIC_SIV_REG, sivr | 0x1FF);
|
||||||
|
|
||||||
|
return apic;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t APIC::ReadFromLocalAPIC(ptrdiff_t offset)
|
||||||
|
{
|
||||||
|
return *(uint32_t*)(m_local_apic + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIC::WriteToLocalAPIC(ptrdiff_t offset, uint32_t data)
|
||||||
|
{
|
||||||
|
*(uint32_t*)(m_local_apic + offset) = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t APIC::IOAPIC::Read(uint8_t offset)
|
||||||
|
{
|
||||||
|
volatile uint32_t* ioapic = (volatile uint32_t*)address;
|
||||||
|
ioapic[0] = offset;
|
||||||
|
return ioapic[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIC::IOAPIC::Write(uint8_t offset, uint32_t data)
|
||||||
|
{
|
||||||
|
volatile uint32_t* ioapic = (volatile uint32_t*)address;
|
||||||
|
ioapic[0] = offset;
|
||||||
|
ioapic[4] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIC::EOI(uint8_t)
|
||||||
|
{
|
||||||
|
WriteToLocalAPIC(LAPIC_EIO_REG, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIC::EnableIrq(uint8_t irq)
|
||||||
|
{
|
||||||
|
uint32_t gsi = m_irq_overrides[irq];
|
||||||
|
|
||||||
|
IOAPIC* ioapic = nullptr;
|
||||||
|
for (IOAPIC& io : m_io_apics)
|
||||||
|
{
|
||||||
|
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
|
||||||
|
{
|
||||||
|
ioapic = &io;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT(ioapic);
|
||||||
|
|
||||||
|
RedirectionEntry redir;
|
||||||
|
redir.lo_dword = ioapic->Read(IOAPIC_REDIRS + gsi * 2);
|
||||||
|
redir.hi_dword = ioapic->Read(IOAPIC_REDIRS + gsi * 2 + 1);
|
||||||
|
|
||||||
|
redir.vector = IRQ_VECTOR_BASE + irq;
|
||||||
|
redir.mask = 0;
|
||||||
|
redir.destination = m_processors.Front().apic_id;
|
||||||
|
|
||||||
|
ioapic->Write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword);
|
||||||
|
ioapic->Write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword);
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIC::GetISR(uint32_t out[8])
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < 8; i++)
|
||||||
|
out[i] = ReadFromLocalAPIC(LAPIC_IS_REG + i * 0x10);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#include <BAN/Queue.h>
|
#include <BAN/Queue.h>
|
||||||
#include <kernel/APIC.h>
|
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/Input.h>
|
#include <kernel/Input.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/kprint.h>
|
#include <kernel/kprint.h>
|
||||||
#include <kernel/PIT.h>
|
#include <kernel/PIT.h>
|
||||||
|
@ -540,7 +540,7 @@ namespace Input
|
||||||
{
|
{
|
||||||
// Register callback and IRQ
|
// Register callback and IRQ
|
||||||
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
|
IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler);
|
||||||
APIC::EnableIRQ(KEYBOARD_IRQ);
|
InterruptController::Get().EnableIrq(KEYBOARD_IRQ);
|
||||||
i8042_controller_command(I8042_ENABLE_FIRST_PORT);
|
i8042_controller_command(I8042_ENABLE_FIRST_PORT);
|
||||||
|
|
||||||
MUST(s_command_queue.Push({
|
MUST(s_command_queue.Push({
|
||||||
|
@ -570,7 +570,7 @@ namespace Input
|
||||||
{
|
{
|
||||||
// Register callback and IRQ
|
// Register callback and IRQ
|
||||||
IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler);
|
IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler);
|
||||||
APIC::EnableIRQ(MOUSE_IRQ);
|
InterruptController::Get().EnableIrq(MOUSE_IRQ);
|
||||||
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
i8042_controller_command(I8042_ENABLE_SECOND_PORT);
|
||||||
|
|
||||||
MUST(s_command_queue.Push({
|
MUST(s_command_queue.Push({
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <BAN/Errors.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
|
#include <kernel/APIC.h>
|
||||||
|
#include <kernel/PIC.h>
|
||||||
|
|
||||||
|
static InterruptController* s_instance = nullptr;
|
||||||
|
|
||||||
|
InterruptController& InterruptController::Get()
|
||||||
|
{
|
||||||
|
ASSERT(s_instance);
|
||||||
|
return *s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterruptController::Initialize(bool force_pic)
|
||||||
|
{
|
||||||
|
ASSERT(s_instance == nullptr);
|
||||||
|
|
||||||
|
PIC::MaskAll();
|
||||||
|
PIC::Remap();
|
||||||
|
|
||||||
|
if (!force_pic)
|
||||||
|
s_instance = APIC::Create();
|
||||||
|
if (s_instance)
|
||||||
|
return;
|
||||||
|
dprintln("Using PIC instead of APIC");
|
||||||
|
s_instance = PIC::Create();
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define PIC1 0x20 /* IO base address for master PIC */
|
#define PIC1 0x20 /* IO base address for master PIC */
|
||||||
#define PIC2 0xA0 /* IO base address for slave PIC */
|
#define PIC2 0xA0 /* IO base address for slave PIC */
|
||||||
#define PIC1_COMMAND PIC1
|
#define PIC1_COMMAND PIC1
|
||||||
|
@ -23,92 +25,86 @@
|
||||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
||||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
||||||
|
|
||||||
|
PIC* PIC::Create()
|
||||||
namespace PIC
|
|
||||||
{
|
{
|
||||||
|
MaskAll();
|
||||||
void Remap()
|
Remap();
|
||||||
{
|
return new PIC;
|
||||||
uint8_t a1 = IO::inb(PIC1_DATA);
|
}
|
||||||
uint8_t a2 = IO::inb(PIC2_DATA);
|
|
||||||
|
void PIC::Remap()
|
||||||
// Start the initialization sequence (in cascade mode)
|
{
|
||||||
IO::outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
|
uint8_t a1 = IO::inb(PIC1_DATA);
|
||||||
IO::io_wait();
|
uint8_t a2 = IO::inb(PIC2_DATA);
|
||||||
IO::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
|
||||||
IO::io_wait();
|
// Start the initialization sequence (in cascade mode)
|
||||||
|
IO::outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||||
// ICW2
|
IO::io_wait();
|
||||||
IO::outb(PIC1_DATA, IRQ_VECTOR_BASE);
|
IO::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||||
IO::io_wait();
|
IO::io_wait();
|
||||||
IO::outb(PIC2_DATA, IRQ_VECTOR_BASE + 0x08);
|
|
||||||
IO::io_wait();
|
// ICW2
|
||||||
|
IO::outb(PIC1_DATA, IRQ_VECTOR_BASE);
|
||||||
// ICW3
|
IO::io_wait();
|
||||||
IO::outb(PIC1_DATA, 4);
|
IO::outb(PIC2_DATA, IRQ_VECTOR_BASE + 0x08);
|
||||||
IO::io_wait();
|
IO::io_wait();
|
||||||
IO::outb(PIC2_DATA, 2);
|
|
||||||
IO::io_wait();
|
// ICW3
|
||||||
|
IO::outb(PIC1_DATA, 4);
|
||||||
// ICW4
|
IO::io_wait();
|
||||||
IO::outb(PIC1_DATA, ICW4_8086);
|
IO::outb(PIC2_DATA, 2);
|
||||||
IO::io_wait();
|
IO::io_wait();
|
||||||
IO::outb(PIC2_DATA, ICW4_8086);
|
|
||||||
IO::io_wait();
|
// ICW4
|
||||||
|
IO::outb(PIC1_DATA, ICW4_8086);
|
||||||
// Restore original masks
|
IO::io_wait();
|
||||||
IO::outb(PIC1_DATA, a1);
|
IO::outb(PIC2_DATA, ICW4_8086);
|
||||||
IO::outb(PIC2_DATA, a2);
|
IO::io_wait();
|
||||||
}
|
|
||||||
|
// Restore original masks
|
||||||
void MaskAll()
|
IO::outb(PIC1_DATA, a1);
|
||||||
{
|
IO::outb(PIC2_DATA, a2);
|
||||||
IO::outb(PIC1_DATA, 0xff);
|
}
|
||||||
IO::outb(PIC2_DATA, 0xff);
|
|
||||||
}
|
void PIC::MaskAll()
|
||||||
|
{
|
||||||
void EOI(uint8_t irq)
|
IO::outb(PIC1_DATA, 0xFF);
|
||||||
{
|
IO::outb(PIC2_DATA, 0xFF);
|
||||||
if (irq >= 8)
|
}
|
||||||
IO::outb(PIC2_COMMAND, PIC_EOI);
|
|
||||||
IO::outb(PIC1_COMMAND, PIC_EOI);
|
void PIC::EOI(uint8_t irq)
|
||||||
}
|
{
|
||||||
|
if (irq >= 8)
|
||||||
void Mask(uint8_t irq) {
|
IO::outb(PIC2_COMMAND, PIC_EOI);
|
||||||
uint16_t port;
|
IO::outb(PIC1_COMMAND, PIC_EOI);
|
||||||
uint8_t value;
|
}
|
||||||
|
|
||||||
if(irq < 8) {
|
void PIC::EnableIrq(uint8_t irq)
|
||||||
port = PIC1_DATA;
|
{
|
||||||
} else {
|
uint16_t port;
|
||||||
port = PIC2_DATA;
|
uint8_t value;
|
||||||
irq -= 8;
|
|
||||||
}
|
if(irq < 8)
|
||||||
value = IO::inb(port) | (1 << irq);
|
{
|
||||||
IO::outb(port, value);
|
port = PIC1_DATA;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
void Unmask(uint8_t irq) {
|
{
|
||||||
uint16_t port;
|
port = PIC2_DATA;
|
||||||
uint8_t value;
|
irq -= 8;
|
||||||
|
}
|
||||||
if(irq < 8) {
|
value = IO::inb(port) & ~(1 << irq);
|
||||||
port = PIC1_DATA;
|
IO::outb(port, value);
|
||||||
} else {
|
}
|
||||||
port = PIC2_DATA;
|
|
||||||
irq -= 8;
|
void PIC::GetISR(uint32_t out[8])
|
||||||
}
|
{
|
||||||
value = IO::inb(port) & ~(1 << irq);
|
memset(out, 0, 8 * sizeof(uint32_t));
|
||||||
IO::outb(port, value);
|
IO::outb(PIC1_COMMAND, 0x0b);
|
||||||
}
|
IO::outb(PIC2_COMMAND, 0x0b);
|
||||||
|
uint16_t isr0 = IO::inb(PIC1_COMMAND);
|
||||||
uint16_t GetISR()
|
uint16_t isr1 = IO::inb(PIC2_COMMAND);
|
||||||
{
|
|
||||||
IO::outb(PIC1_COMMAND, 0x0b);
|
uintptr_t addr = (uintptr_t)out + IRQ_VECTOR_BASE / 8;
|
||||||
IO::outb(PIC2_COMMAND, 0x0b);
|
*(uint16_t*)addr = (isr1 << 8) | isr0;
|
||||||
uint8_t isr0 = IO::inb(PIC1_COMMAND);
|
|
||||||
uint8_t isr1 = IO::inb(PIC2_COMMAND);
|
|
||||||
return (isr1 << 8) | isr0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/IO.h>
|
#include <kernel/IO.h>
|
||||||
#include <kernel/kprint.h>
|
#include <kernel/kprint.h>
|
||||||
#include <kernel/APIC.h>
|
|
||||||
|
|
||||||
#define IRQ_TIMER 0
|
#define IRQ_TIMER 0
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ namespace PIT
|
||||||
|
|
||||||
IDT::register_irq_handler(IRQ_TIMER, clock_handle);
|
IDT::register_irq_handler(IRQ_TIMER, clock_handle);
|
||||||
|
|
||||||
APIC::EnableIRQ(IRQ_TIMER);
|
InterruptController::Get().EnableIrq(IRQ_TIMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
#include <BAN/Memory.h>
|
|
||||||
#include <kernel/APIC.h>
|
|
||||||
#include <kernel/GDT.h>
|
|
||||||
#include <kernel/IDT.h>
|
#include <kernel/IDT.h>
|
||||||
#include <kernel/Input.h>
|
#include <kernel/Input.h>
|
||||||
|
#include <kernel/InterruptController.h>
|
||||||
#include <kernel/kmalloc.h>
|
#include <kernel/kmalloc.h>
|
||||||
#include <kernel/kprint.h>
|
#include <kernel/kprint.h>
|
||||||
#include <kernel/MMU.h>
|
#include <kernel/MMU.h>
|
||||||
#include <kernel/multiboot.h>
|
#include <kernel/multiboot.h>
|
||||||
#include <kernel/PIC.h>
|
#include <kernel/PIC.h>
|
||||||
#include <kernel/PIT.h>
|
#include <kernel/PIT.h>
|
||||||
#include <kernel/RTC.h>
|
|
||||||
#include <kernel/Serial.h>
|
#include <kernel/Serial.h>
|
||||||
#include <kernel/Shell.h>
|
#include <kernel/Shell.h>
|
||||||
#include <kernel/TTY.h>
|
#include <kernel/TTY.h>
|
||||||
|
@ -81,8 +78,9 @@ extern "C" void kernel_main()
|
||||||
dprintln("VESA initialized");
|
dprintln("VESA initialized");
|
||||||
TTY* tty1 = new TTY(terminal_driver);
|
TTY* tty1 = new TTY(terminal_driver);
|
||||||
|
|
||||||
APIC::Initialize(cmdline.force_pic);
|
InterruptController::Initialize(cmdline.force_pic);
|
||||||
dprintln("APIC initialized");
|
dprintln("Interrupt controller initialized");
|
||||||
|
|
||||||
PIT::initialize();
|
PIT::initialize();
|
||||||
dprintln("PIT initialized");
|
dprintln("PIT initialized");
|
||||||
if (!Input::initialize())
|
if (!Input::initialize())
|
||||||
|
|
Loading…
Reference in New Issue