From 1c1fc65c7cf78aefcd88b951eb7ca478d83fe0a8 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 1 Apr 2025 22:55:05 +0300 Subject: [PATCH] Kernel: Add API to reserve GSI instead of irq This also fixes a bug with IOAPIC gsi_base != 0 --- kernel/include/kernel/APIC.h | 2 ++ kernel/kernel/APIC.cpp | 52 +++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/kernel/include/kernel/APIC.h b/kernel/include/kernel/APIC.h index 2054be6b..194e1689 100644 --- a/kernel/include/kernel/APIC.h +++ b/kernel/include/kernel/APIC.h @@ -23,6 +23,8 @@ namespace Kernel virtual void broadcast_ipi() override; virtual void enable() override; + BAN::ErrorOr reserve_gsi(uint32_t gsi); + void initialize_timer(); private: diff --git a/kernel/kernel/APIC.cpp b/kernel/kernel/APIC.cpp index a847fac9..7e1a832e 100644 --- a/kernel/kernel/APIC.cpp +++ b/kernel/kernel/APIC.cpp @@ -458,7 +458,7 @@ namespace Kernel { SpinLockGuard _(m_lock); - uint32_t gsi = m_irq_overrides[irq]; + const uint32_t gsi = m_irq_overrides[irq]; { int byte = gsi / 8; @@ -477,9 +477,11 @@ namespace Kernel } ASSERT(ioapic); + const uint32_t pin = gsi - ioapic->gsi_base; + RedirectionEntry redir; - redir.lo_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2); - redir.hi_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2 + 1); + redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2); + redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1); ASSERT(redir.mask); // TODO: handle overlapping interrupts redir.vector = IRQ_VECTOR_BASE + irq; @@ -487,8 +489,8 @@ namespace Kernel // FIXME: distribute IRQs more evenly? redir.destination = Kernel::Processor::bsb_id().as_u32(); - ioapic->write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword); - ioapic->write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword); + ioapic->write(IOAPIC_REDIRS + pin * 2, redir.lo_dword); + ioapic->write(IOAPIC_REDIRS + pin * 2 + 1, redir.hi_dword); } bool APIC::is_in_service(uint8_t irq) @@ -504,35 +506,59 @@ namespace Kernel { SpinLockGuard _(m_lock); - uint32_t gsi = m_irq_overrides[irq]; + const uint32_t gsi = m_irq_overrides[irq]; - IOAPIC* ioapic = nullptr; - for (IOAPIC& io : m_io_apics) + bool found_ioapic = false; + for (const auto& io : m_io_apics) { if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs) { - ioapic = &io; + found_ioapic = true; break; } } - if (!ioapic) + if (!found_ioapic) { - dwarnln("Cannot enable irq {} for APIC", irq); - return BAN::Error::from_errno(EFAULT); + dwarnln("No IOAPIC for GSI {}", gsi); + return BAN::Error::from_errno(EINVAL); } int byte = gsi / 8; int bit = gsi % 8; if (m_reserved_gsis[byte] & (1 << bit)) { - dwarnln("irq {} is already reserved", irq); + dwarnln("GSI {} is already reserved", gsi); return BAN::Error::from_errno(EFAULT); } m_reserved_gsis[byte] |= 1 << bit; return {}; } + // FIXME: rewrite gsi and vector reserving + // this is a hack to allow direct GSI reservation + BAN::ErrorOr APIC::reserve_gsi(uint32_t gsi) + { + dwarnln("TRYING TO RESERVE GSI {}", gsi); + + size_t irq = 0; + for (; irq < 0x100; irq++) + if (m_irq_overrides[irq] == gsi) + break; + + if (irq == 0x100) + { + dwarnln("TODO: reserve GSI not accessible through overrides"); + return BAN::Error::from_errno(ENOTSUP); + } + + dwarnln(" matches IRQ {}", irq); + + TRY(reserve_irq(irq)); + + return irq; + } + BAN::Optional APIC::get_free_irq() { SpinLockGuard _(m_lock);