diff --git a/src/hulk/apic.d b/src/hulk/apic.d index 0dcb877..4dc9a9b 100644 --- a/src/hulk/apic.d +++ b/src/hulk/apic.d @@ -52,13 +52,23 @@ struct apic 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 @@ -68,6 +78,19 @@ struct apic apic_registers.lvt_lint[0].value = idt.INT_LAPIC_LINT0; apic_registers.lvt_lint[1].value = idt.INT_LAPIC_LINT1; apic_registers.divide_configuration.value = 3u; + for (size_t i = 0u; i < 24u; i++) + { + configure_io_apic_irq(i, i + 0x40u); + } + } + + 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; } private static void eoi() diff --git a/src/hulk/hulk.d b/src/hulk/hulk.d index b6300ac..304e302 100644 --- a/src/hulk/hulk.d +++ b/src/hulk/hulk.d @@ -21,6 +21,7 @@ import hulk.pic; import hulk.acpi; import hulk.apic; import hulk.rtc; +import hulk.pit; extern extern(C) __gshared ubyte _hulk_bss_size; @@ -75,6 +76,7 @@ void hulk_start() acpi.initialize(hulk_header.bootinfo.acpi_xsdt_phys); apic.initialize(); rtc.initialize(); + pit.initialize(); sti(); for (;;) diff --git a/src/hulk/idt.d b/src/hulk/idt.d index 686119c..c929eb4 100644 --- a/src/hulk/idt.d +++ b/src/hulk/idt.d @@ -13,8 +13,8 @@ import hulk.rtc; struct idt { - /* IRQ 0 is interrupt 32 (0x20). */ - public static enum ulong INT_RTC = 0x28u; /* IRQ 8 */ + /* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */ + public static enum ulong INT_RTC = 0x48u; /* IRQ 8 */ public static enum ulong INT_LAPIC_TIMER = 0x70u; public static enum ulong INT_LAPIC_LINT0 = 0x71u; diff --git a/src/hulk/pit.d b/src/hulk/pit.d new file mode 100644 index 0000000..6bd4e48 --- /dev/null +++ b/src/hulk/pit.d @@ -0,0 +1,42 @@ +/** + * PIT (Programmable Interval Timer) functionality. + */ +module hulk.pit; + +import hulk.cpu; +import hulk.klog; + +struct pit +{ + /** PIT input frequency in 1/1000 Hz. */ + private enum ulong PIT_FREQUENCY_1000HZ = 1_193_181_667u; + private enum ulong TARGET_INTERRUPT_HZ = 100u; + private enum ulong TARGET_INTERRUPT_1000HZ = TARGET_INTERRUPT_HZ * 1000u; + private enum ulong PIT_DIVIDER = (PIT_FREQUENCY_1000HZ + TARGET_INTERRUPT_1000HZ / 2u) / TARGET_INTERRUPT_1000HZ; + + /** PIT channel 0 I/O port. */ + private enum ubyte PORT_CH_0 = 0x40u; + /** PIT channel 1 I/O port. */ + private enum ubyte PORT_CH_1 = 0x41u; + /** PIT channel 2 I/O port. */ + private enum ubyte PORT_CH_2 = 0x42u; + /** PIT mode/command register I/O port. */ + private enum ubyte PORT_MC = 0x43u; + + private enum ubyte MC_CH_0 = 0x00u; + private enum ubyte MC_LO_HI = 0x30u; + private enum ubyte MC_RATE_GENERATOR = 0x04u; + private enum ubyte MC_BINARY = 0x00u; + + public static void initialize() + { + out8(PORT_MC, MC_CH_0 | MC_LO_HI | MC_RATE_GENERATOR | MC_BINARY); + out8(PORT_CH_0, PIT_DIVIDER & 0xFFu); + out8(PORT_CH_0, PIT_DIVIDER >> 8u); + } + + public static void isr() + { + klog.writefln("PIT ISR"); + } +}