/* * Copyright (c) 2026, Chloe M. * Provided under the BSD-3 clause. * * Description: IRQ chip management * Author: Chloe M. */ #include #include #include #include /* PIC data ports */ #define PIC_MASTER_DATA 0x21 #define PIC_SLAVE_DATA 0xA1 #define DTRACE(Fmt, ...) \ TRACE("[ IRQCHIP ]: " Fmt, ##__VA_ARGS__) /* Set if dual i8259 is present */ #define MADT_PCAT_COMPAT BIT(0) /* Local APIC list */ static ACPI_LOCAL_APIC *LapicList[LAPIC_MAX]; static USIZE LapicCount = 0; /* * Append a Local APIC descriptor * * @Lapic: LAPIC to append */ static VOID AppendLapic(ACPI_LOCAL_APIC *Lapic) { if (Lapic == NULL) { return; } if (LapicCount >= LAPIC_MAX) { return; } if (LapicCount < 4) { DTRACE("lapic%d at cpu%d\n", Lapic->ApicId, Lapic->ProcessorId); } LapicList[LapicCount++] = Lapic; } ACPI_LOCAL_APIC * MdLapicByIndex(USIZE Index) { if (Index >= LapicCount) { return NULL; } return LapicList[Index]; } VOID MdIrqChipInit(VOID) { ACPI_MADT *Madt; ACPI_APIC_HEADER *ApicHdr; ACPI_LOCAL_APIC *Lapic; UCHAR *MadtCur, *MadtEnd; Madt = AcpiQuery("APIC"); if (Madt == NULL) { KeKnot( KNOT_UNBOUND_RSRC, "could not locate ACPI MADT\n" ); } /* * If we have a dual-i8259 configuration present on the * machine, we'll want to disable it so it doesn't mess * up Local APIC operation and such. */ if (ISSET(Madt->Flags, MADT_PCAT_COMPAT)) { DTRACE("detected dual i8259; disabling...\n"); MdOutb(PIC_MASTER_DATA, 0xFF); MdOutb(PIC_SLAVE_DATA, 0xFF); } MadtCur = (UCHAR *)(Madt + 1); MadtEnd = (UCHAR *)Madt + Madt->Header.Length; while (MadtCur < MadtEnd) { ApicHdr = (ACPI_APIC_HEADER *)MadtCur; switch (ApicHdr->Type) { case APIC_TYPE_LOCAL_APIC: Lapic = (ACPI_LOCAL_APIC *)ApicHdr; AppendLapic(Lapic); break; } MadtCur += ApicHdr->Length; } }