Route I/O APIC interrupts, enable RTC tick interrupt

This commit is contained in:
Josh Holtrop 2022-12-16 00:32:49 -05:00
parent 9adc248225
commit 4081a220ef
2 changed files with 64 additions and 16 deletions

View File

@ -7,11 +7,14 @@ import hulk.klog;
import hulk.hurl; import hulk.hurl;
import hulk.acpi; import hulk.acpi;
import hulk.idt; import hulk.idt;
import hulk.rtc;
struct apic struct apic
{ {
private enum uint PERIODIC_MODE = 0x2_0000u; private enum uint PERIODIC_MODE = 0x2_0000u;
private enum ulong IRQ_RTC = 8u;
static struct ApicRegister static struct ApicRegister
{ {
public uint value; public uint value;
@ -52,31 +55,60 @@ struct apic
ApicRegister divide_configuration; ApicRegister divide_configuration;
} }
static struct IoApicRegisters
{
ApicRegister address;
ApicRegister data;
}
private static __gshared ApicRegisters * apic_registers; private static __gshared ApicRegisters * apic_registers;
private static __gshared IoApicRegisters * io_apic_registers;
public static void initialize() public static void initialize()
{ {
apic_registers = cast(ApicRegisters *)acpi.apic_address; apic_registers = cast(ApicRegisters *)acpi.apic_address;
io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u;
hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers, hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers,
PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE); PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE);
hurl.map(cast(ulong)io_apic_registers, cast(ulong)io_apic_registers,
PT_WRITABLE | PT_WRITE_THROUGH | PT_DISABLE_CACHE | PT_NO_EXECUTE);
klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.value); klog.writefln("LAPIC ID: 0x%08x", apic_registers.lapic_id.value);
klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.value); klog.writefln("LAPIC version: 0x%08x", apic_registers.lapic_version.value);
/* Enable local APIC to receive interrupts and set spurious interrupt /* Enable local APIC to receive interrupts and set spurious interrupt
* vector to 0xFF. */ * vector to 0xFF. */
apic_registers.spurious_interrupt_vector.value = 0x1FFu; apic_registers.spurious_interrupt_vector.value = 0x100u | idt.INT_APIC_SPURIOUS;
apic_registers.lvt_timer.value = idt.EXCEPTION_LAPIC_TIMER | PERIODIC_MODE; apic_registers.lvt_timer.value = idt.INT_APIC_TIMER;
apic_registers.lvt_lint[0].value = idt.EXCEPTION_LAPIC_LINT0; apic_registers.lvt_lint[0].value = idt.INT_APIC_LINT0;
apic_registers.lvt_lint[1].value = idt.EXCEPTION_LAPIC_LINT1; apic_registers.lvt_lint[1].value = idt.INT_APIC_LINT1;
apic_registers.divide_configuration.value = 3u; /* Enable RTC interrupt. */
configure_io_apic_irq(IRQ_RTC, idt.INT_APIC_BASE + IRQ_RTC);
} }
private static void eoi() private static void configure_io_apic_irq(size_t io_apic_irq, size_t interrupt_id)
{
ulong entry = interrupt_id;
io_apic_registers.address.value = cast(uint)(0x10u + io_apic_irq * 2u);
io_apic_registers.data.value = entry & 0xFFFF_FFFFu;
io_apic_registers.address.value = cast(uint)(0x10u + io_apic_irq * 2u + 1u);
io_apic_registers.data.value = entry >> 32u;
}
public static void eoi()
{ {
apic_registers.eoi.value = 0u; apic_registers.eoi.value = 0u;
} }
public static void isr(ulong vector) public static void isr(ulong vector)
{ {
switch (vector)
{
case idt.INT_APIC_BASE + IRQ_RTC:
rtc.isr();
break;
default:
break;
}
eoi(); eoi();
} }
} }

View File

@ -12,9 +12,14 @@ import hulk.apic;
struct idt struct idt
{ {
public static enum ulong EXCEPTION_LAPIC_TIMER = 0x70u; /* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */
public static enum ulong EXCEPTION_LAPIC_LINT0 = 0x71u; public static enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */
public static enum ulong EXCEPTION_LAPIC_LINT1 = 0x72u; public static enum ulong INT_APIC_COUNT = 24u;
public static enum ulong INT_APIC_TIMER = 0x70u;
public static enum ulong INT_APIC_LINT0 = 0x71u;
public static enum ulong INT_APIC_LINT1 = 0x72u;
public static enum ulong INT_APIC_SPURIOUS = 0xFFu;
struct idtr_t struct idtr_t
{ {
@ -99,19 +104,30 @@ struct idt
public extern(C) void isr(ulong vector, ulong arg) public extern(C) void isr(ulong vector, ulong arg)
{ {
if ((idt.EXCEPTION_LAPIC_TIMER <= vector) && (vector <= idt.EXCEPTION_LAPIC_LINT1)) if ((vector >= idt.INT_APIC_BASE) && (vector < (idt.INT_APIC_BASE + idt.INT_APIC_COUNT)))
{ {
apic.isr(vector); apic.isr(vector);
} }
else else
{ {
console.clear(); switch (vector)
fb.clear(0xFF8000u);
klog.writefln("ISR %u, 0x%x", vector, arg);
__asm("cli", "");
for (;;)
{ {
__asm("hlt", ""); case idt.INT_APIC_TIMER:
case idt.INT_APIC_LINT0:
case idt.INT_APIC_LINT1:
case idt.INT_APIC_SPURIOUS:
apic.isr(vector);
break;
default:
console.clear();
fb.clear(0xFF8000u);
klog.writefln("ISR %u, 0x%x", vector, arg);
__asm("cli", "");
for (;;)
{
__asm("hlt", "");
}
} }
} }
} }