#include #include #include #include #include #include #include #include #include #define IOAPICS_MAX 24 #define INTERRUPT_SRC_OVERRIDES_MAX 24 static struct acpi_madt_ioapic apics[IOAPICS_MAX]; /* clang-format off */ static struct acpi_madt_interrupt_source_override intr_src_overrides[INTERRUPT_SRC_OVERRIDES_MAX]; /* clang-format on */ static size_t ioapic_entries = 0; static size_t intr_src_override_entries = 0; extern void amd64_spin (void); static uint32_t amd64_ioapic_read (uintptr_t vaddr, uint32_t reg) { *(volatile uint32_t*)vaddr = reg; return *(volatile uint32_t*)(vaddr + 0x10); } static void amd64_ioapic_write (uintptr_t vaddr, uint32_t reg, uint32_t value) { *(volatile uint32_t*)vaddr = reg; *(volatile uint32_t*)(vaddr + 0x10) = value; } static struct acpi_madt_ioapic* amd64_ioapic_find (uint8_t irq) { struct acpi_madt_ioapic* apic = NULL; struct limine_hhdm_response* hhdm = limine_hhdm_request.response; for (size_t i = 0; i < ioapic_entries; i++) { apic = &apics[i]; uint32_t version = amd64_ioapic_read ( (uintptr_t)hhdm->offset + (uintptr_t)apic->address, 1); uint32_t max = (version >> 16); if ((apic->gsi_base <= irq) && ((apic->gsi_base + max) > irq)) break; } return apic; } void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags, uint64_t lapic_id) { struct acpi_madt_ioapic* apic; struct acpi_madt_interrupt_source_override* override; bool found_override = false; struct limine_hhdm_response* hhdm = limine_hhdm_request.response; for (size_t i = 0; i < intr_src_override_entries; i++) { override = &intr_src_overrides[i]; if (override->source == irq) { found_override = true; break; } } uint64_t calc_flags = (lapic_id << 56) | (flags) | (vec & 0xFF); if (found_override) { uint8_t polarity = ((override->flags & 0x03) == 0x03) ? 1 : 0; uint8_t mode = (((override->flags >> 2) & 0x03) == 0x03) ? 1 : 0; calc_flags = (lapic_id << 56) | (mode << 15) | (polarity << 14) | (vec & 0xFF) | flags; } apic = amd64_ioapic_find (irq); if (apic == NULL) return; uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10; amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg, (uint32_t)calc_flags); amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg + 1, (uint32_t)(calc_flags >> 32)); } void amd64_ioapic_mask (uint8_t irq) { struct acpi_madt_ioapic* apic; struct limine_hhdm_response* hhdm = limine_hhdm_request.response; apic = amd64_ioapic_find (irq); if (apic == NULL) return; uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10; uint32_t value = amd64_ioapic_read ( (uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg); amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg, value | (1 << 16)); } void amd64_ioapic_unmask (uint8_t irq) { struct acpi_madt_ioapic* apic; struct limine_hhdm_response* hhdm = limine_hhdm_request.response; apic = amd64_ioapic_find (irq); if (apic == NULL) return; uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10; uint32_t value = amd64_ioapic_read ( (uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg); amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg, value & ~(1 << 16)); } void amd64_ioapic_init (void) { struct limine_hhdm_response* hhdm = limine_hhdm_request.response; struct uacpi_table apic_table; uacpi_status status = uacpi_table_find_by_signature (ACPI_MADT_SIGNATURE, &apic_table); if (status != UACPI_STATUS_OK) { DEBUG ("Could not find MADT table!\n"); amd64_spin (); } struct acpi_madt* apic = (struct acpi_madt*)apic_table.virt_addr; struct acpi_entry_hdr* current = (struct acpi_entry_hdr*)apic->entries; for (;;) { if ((uintptr_t)current >= ((uintptr_t)apic->entries + apic->hdr.length - sizeof (struct acpi_madt))) break; switch (current->type) { case ACPI_MADT_ENTRY_TYPE_IOAPIC: { struct acpi_madt_ioapic* ioapic = (struct acpi_madt_ioapic*)current; mm_map_kernel_page ((uintptr_t)ioapic->address, (uintptr_t)hhdm->offset + (uintptr_t)ioapic->address, MM_PG_USER | MM_PG_RW); apics[ioapic_entries++] = *ioapic; } break; case ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE: { struct acpi_madt_interrupt_source_override* override = (struct acpi_madt_interrupt_source_override*)current; intr_src_overrides[intr_src_override_entries++] = *override; } break; } current = (struct acpi_entry_hdr*)((uintptr_t)current + current->length); } }