Kernel: Add API to reserve GSI instead of irq

This also fixes a bug with IOAPIC gsi_base != 0
This commit is contained in:
Bananymous 2025-04-01 22:55:05 +03:00
parent ba74b352bd
commit 1c1fc65c7c
2 changed files with 41 additions and 13 deletions

View File

@ -23,6 +23,8 @@ namespace Kernel
virtual void broadcast_ipi() override; virtual void broadcast_ipi() override;
virtual void enable() override; virtual void enable() override;
BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi);
void initialize_timer(); void initialize_timer();
private: private:

View File

@ -458,7 +458,7 @@ namespace Kernel
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
uint32_t gsi = m_irq_overrides[irq]; const uint32_t gsi = m_irq_overrides[irq];
{ {
int byte = gsi / 8; int byte = gsi / 8;
@ -477,9 +477,11 @@ namespace Kernel
} }
ASSERT(ioapic); ASSERT(ioapic);
const uint32_t pin = gsi - ioapic->gsi_base;
RedirectionEntry redir; RedirectionEntry redir;
redir.lo_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2); redir.lo_dword = ioapic->read(IOAPIC_REDIRS + pin * 2);
redir.hi_dword = ioapic->read(IOAPIC_REDIRS + gsi * 2 + 1); redir.hi_dword = ioapic->read(IOAPIC_REDIRS + pin * 2 + 1);
ASSERT(redir.mask); // TODO: handle overlapping interrupts ASSERT(redir.mask); // TODO: handle overlapping interrupts
redir.vector = IRQ_VECTOR_BASE + irq; redir.vector = IRQ_VECTOR_BASE + irq;
@ -487,8 +489,8 @@ namespace Kernel
// FIXME: distribute IRQs more evenly? // FIXME: distribute IRQs more evenly?
redir.destination = Kernel::Processor::bsb_id().as_u32(); redir.destination = Kernel::Processor::bsb_id().as_u32();
ioapic->write(IOAPIC_REDIRS + gsi * 2, redir.lo_dword); ioapic->write(IOAPIC_REDIRS + pin * 2, redir.lo_dword);
ioapic->write(IOAPIC_REDIRS + gsi * 2 + 1, redir.hi_dword); ioapic->write(IOAPIC_REDIRS + pin * 2 + 1, redir.hi_dword);
} }
bool APIC::is_in_service(uint8_t irq) bool APIC::is_in_service(uint8_t irq)
@ -504,35 +506,59 @@ namespace Kernel
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
uint32_t gsi = m_irq_overrides[irq]; const uint32_t gsi = m_irq_overrides[irq];
IOAPIC* ioapic = nullptr; bool found_ioapic = false;
for (IOAPIC& io : m_io_apics) for (const auto& io : m_io_apics)
{ {
if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs) if (io.gsi_base <= gsi && gsi <= io.gsi_base + io.max_redirs)
{ {
ioapic = &io; found_ioapic = true;
break; break;
} }
} }
if (!ioapic) if (!found_ioapic)
{ {
dwarnln("Cannot enable irq {} for APIC", irq); dwarnln("No IOAPIC for GSI {}", gsi);
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EINVAL);
} }
int byte = gsi / 8; int byte = gsi / 8;
int bit = gsi % 8; int bit = gsi % 8;
if (m_reserved_gsis[byte] & (1 << bit)) 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); return BAN::Error::from_errno(EFAULT);
} }
m_reserved_gsis[byte] |= 1 << bit; m_reserved_gsis[byte] |= 1 << bit;
return {}; return {};
} }
// FIXME: rewrite gsi and vector reserving
// this is a hack to allow direct GSI reservation
BAN::ErrorOr<uint8_t> 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<uint8_t> APIC::get_free_irq() BAN::Optional<uint8_t> APIC::get_free_irq()
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);