Files
hos/src/hulk/apic.d
T
josh 25ee1775f0 Capitalize namespacing structs
This helps to avoid name clashes when breaking up modules into packages.
2023-01-01 17:34:41 -05:00

115 lines
3.5 KiB
D

/**
* APIC (Advanced Programmable Interrupt Controller) functionality.
*/
module hulk.apic;
import hulk.klog;
import hulk.hurl;
import hulk.acpi;
import hulk.idt;
import hulk.rtc;
struct Apic
{
private enum uint PERIODIC_MODE = 0x2_0000u;
private enum ulong IRQ_RTC = 8u;
static struct ApicRegister
{
public uint value;
alias value this;
private ubyte[12] _padding;
}
static struct ApicRegisters
{
ApicRegister[2] _reserved0;
ApicRegister lapic_id;
ApicRegister lapic_version;
ApicRegister[4] _reserved1;
ApicRegister task_priority;
ApicRegister arbitration_priority;
ApicRegister processor_priority;
ApicRegister eoi;
ApicRegister remote_read;
ApicRegister logical_destination;
ApicRegister destination_format;
ApicRegister spurious_interrupt_vector;
ApicRegister[8] in_service;
ApicRegister[8] trigger_mode;
ApicRegister[8] interrupt_request;
ApicRegister error_status;
ApicRegister[6] _reserved2;
ApicRegister lvt_cmci;
ApicRegister[2] interrupt_command;
ApicRegister lvt_timer;
ApicRegister lvt_thermal_sensor;
ApicRegister lvt_performance_monitoring_counters;
ApicRegister[2] lvt_lint;
ApicRegister lvt_error;
ApicRegister initial_count;
ApicRegister current_count;
ApicRegister[4] _reserved3;
ApicRegister divide_configuration;
}
static struct IoApicRegisters
{
ApicRegister address;
ApicRegister data;
}
private static __gshared ApicRegisters * apic_registers;
private static __gshared IoApicRegisters * io_apic_registers;
public static void initialize()
{
apic_registers = cast(ApicRegisters *)Acpi.apic_address;
io_apic_registers = cast(IoApicRegisters *)0xFEC0_0000u;
Hurl.map(cast(ulong)apic_registers, cast(ulong)apic_registers,
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 version: 0x%08x", apic_registers.lapic_version.value);
/* Enable local APIC to receive interrupts and set spurious interrupt
* vector to 0xFF. */
apic_registers.spurious_interrupt_vector.value = 0x100u | Idt.INT_APIC_SPURIOUS;
apic_registers.lvt_timer.value = Idt.INT_APIC_TIMER;
apic_registers.lvt_lint[0].value = Idt.INT_APIC_LINT0;
apic_registers.lvt_lint[1].value = Idt.INT_APIC_LINT1;
/* Enable RTC interrupt. */
configure_io_apic_irq(IRQ_RTC, Idt.INT_APIC_BASE + IRQ_RTC);
}
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;
}
public static void isr(ulong vector)
{
switch (vector)
{
case Idt.INT_APIC_BASE + IRQ_RTC:
Rtc.isr();
break;
default:
break;
}
eoi();
}
}