diff --git a/kernel/src/arch/x86_64/CPU.cpp b/kernel/src/arch/x86_64/CPU.cpp index d7733861..4c4e519c 100644 --- a/kernel/src/arch/x86_64/CPU.cpp +++ b/kernel/src/arch/x86_64/CPU.cpp @@ -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) { diff --git a/kernel/src/arch/x86_64/CPU.h b/kernel/src/arch/x86_64/CPU.h index a2efee77..def5d41e 100644 --- a/kernel/src/arch/x86_64/CPU.h +++ b/kernel/src/arch/x86_64/CPU.h @@ -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; }; diff --git a/kernel/src/arch/x86_64/disk/ATA.cpp b/kernel/src/arch/x86_64/disk/ATA.cpp index 412b1c9d..3a0d4837 100644 --- a/kernel/src/arch/x86_64/disk/ATA.cpp +++ b/kernel/src/arch/x86_64/disk/ATA.cpp @@ -14,7 +14,7 @@ SharedPtr 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++) { diff --git a/kernel/src/arch/x86_64/disk/ATA.h b/kernel/src/arch/x86_64/disk/ATA.h index c86cf4d9..9ceabcf5 100644 --- a/kernel/src/arch/x86_64/disk/ATA.h +++ b/kernel/src/arch/x86_64/disk/ATA.h @@ -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; diff --git a/kernel/src/arch/x86_64/init/PIC.cpp b/kernel/src/arch/x86_64/init/PIC.cpp index 35ca6481..03a82fce 100644 --- a/kernel/src/arch/x86_64/init/PIC.cpp +++ b/kernel/src/arch/x86_64/init/PIC.cpp @@ -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)); }