kernel/ATA: Route interrupts to the correct drive
All checks were successful
continuous-integration/drone/pr Build is passing

This commit is contained in:
apio 2023-05-27 19:16:01 +02:00
parent 2722bd73af
commit fa47237ddb
Signed by: apio
GPG Key ID: B8A7D06E42258954
5 changed files with 23 additions and 12 deletions

View File

@ -180,7 +180,7 @@ extern "C" void arch_interrupt_entry(Registers* regs)
if (regs->isr < 32) handle_x86_exception(regs);
else if (regs->isr >= 32 && regs->isr < 48) // IRQ from the PIC
{
u64 irq = regs->error;
u64 irq = regs->irq;
auto handler = irq_handlers[irq];
if (!handler.function)
{

View File

@ -5,7 +5,11 @@ struct Registers // Saved CPU registers for x86-64
{
u64 r15, r14, r13, r12, r11, r10, r9, r8;
u64 rbp, rdi, rsi, rdx, rcx, rbx, rax;
u64 isr, error;
u64 isr;
union {
u64 error;
u64 irq;
};
u64 rip, cs, rflags, rsp, ss;
};

View File

@ -14,7 +14,7 @@ SharedPtr<ATA::Controller> g_controller;
static void irq_handler(Registers* regs, void* ctx)
{
((ATA::Channel*)ctx)->irq_handler(regs);
((ATA::Controller*)ctx)->irq_handler(regs);
}
static usize copy_ata_string(char* out, u16* in, usize size)
@ -70,6 +70,12 @@ namespace ATA
return m_secondary_channel.initialize();
}
void Controller::irq_handler(Registers* regs)
{
if (regs->irq == m_primary_channel.irq_line()) m_primary_channel.irq_handler(regs);
if (regs->irq == m_secondary_channel.irq_line()) m_secondary_channel.irq_handler(regs);
}
Controller::Controller(const PCI::Device& device)
: m_device(device), m_primary_channel(this, 0, {}), m_secondary_channel(this, 1, {})
{
@ -150,7 +156,7 @@ namespace ATA
void Channel::irq_handler(Registers*)
{
// FIXME: Read the Busmaster register to make sure the IRQ is for this channel.
if (!(read_bm(BusmasterRegister::Status) & BMS_IRQPending)) return;
if (m_current_drive < 2 && m_drives[m_current_drive]) m_drives[m_current_drive]->irq_handler();
@ -314,13 +320,7 @@ namespace ATA
}
}
bool ok = CPU::register_interrupt(m_interrupt_line, ::irq_handler, this);
if (!ok)
{
kerrorln("ata: Failed to register IRQ handler for ATA channel %d (IRQ %d)", m_channel_index,
m_interrupt_line);
return false;
}
CPU::register_interrupt(m_interrupt_line, ::irq_handler, m_controller);
for (u8 drive = 0; drive < 2; drive++)
{

View File

@ -231,6 +231,11 @@ namespace ATA
bool wait_for_irq_or_timeout(u64 timeout);
void irq_handler(Registers*);
u8 irq_line()
{
return m_interrupt_line;
}
void select(u8 drive);
bool initialize();
@ -269,6 +274,8 @@ namespace ATA
bool initialize();
void irq_handler(Registers*);
private:
Controller(const PCI::Device& device);
PCI::Device m_device;

View File

@ -58,5 +58,5 @@ void pic_eoi(unsigned char irq)
void pic_eoi(Registers* regs)
{
pic_eoi((unsigned char)(regs->error)); // On IRQs, the error code is the IRQ number
pic_eoi((unsigned char)(regs->irq));
}