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 enable() override;
BAN::ErrorOr<uint8_t> reserve_gsi(uint32_t gsi);
void initialize_timer();
private:

View File

@ -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<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()
{
SpinLockGuard _(m_lock);