kernel/ATA: Route interrupts to the correct drive
Some checks failed
continuous-integration/drone/pr Build is failing

This commit is contained in:
apio 2023-05-27 19:16:01 +02:00
parent 7545cb055c
commit cbb44a5a10
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); if (regs->isr < 32) handle_x86_exception(regs);
else if (regs->isr >= 32 && regs->isr < 48) // IRQ from the PIC 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]; auto handler = irq_handlers[irq];
if (!handler.function) 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 r15, r14, r13, r12, r11, r10, r9, r8;
u64 rbp, rdi, rsi, rdx, rcx, rbx, rax; u64 rbp, rdi, rsi, rdx, rcx, rbx, rax;
u64 isr, error; u64 isr;
union {
u64 error;
u64 irq;
};
u64 rip, cs, rflags, rsp, ss; 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) 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) static usize copy_ata_string(char* out, u16* in, usize size)
@ -70,6 +70,12 @@ namespace ATA
return m_secondary_channel.initialize(); 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) Controller::Controller(const PCI::Device& device)
: m_device(device), m_primary_channel(this, 0, {}), m_secondary_channel(this, 1, {}) : m_device(device), m_primary_channel(this, 0, {}), m_secondary_channel(this, 1, {})
{ {
@ -150,7 +156,7 @@ namespace ATA
void Channel::irq_handler(Registers*) 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(); 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); CPU::register_interrupt(m_interrupt_line, ::irq_handler, m_controller);
if (!ok)
{
kerrorln("ata: Failed to register IRQ handler for ATA channel %d (IRQ %d)", m_channel_index,
m_interrupt_line);
return false;
}
for (u8 drive = 0; drive < 2; drive++) for (u8 drive = 0; drive < 2; drive++)
{ {

View File

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

View File

@ -58,5 +58,5 @@ void pic_eoi(unsigned char irq)
void pic_eoi(Registers* regs) 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));
} }