diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index a81bb6b8b5..949dc37e2c 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -56,6 +56,7 @@ set(KERNEL_SOURCES Storage/AHCIPort.cpp Storage/AHCIPortHandler.cpp Storage/SATADiskDevice.cpp + Storage/BMIDEChannel.cpp Storage/IDEController.cpp Storage/IDEChannel.cpp Storage/PATADiskDevice.cpp diff --git a/Kernel/Storage/BMIDEChannel.cpp b/Kernel/Storage/BMIDEChannel.cpp new file mode 100644 index 0000000000..0ee8c0d80e --- /dev/null +++ b/Kernel/Storage/BMIDEChannel.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2021, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +namespace Kernel { + +UNMAP_AFTER_INIT NonnullRefPtr BMIDEChannel::create(const IDEController& ide_controller, IDEChannel::IOAddressGroup io_group, IDEChannel::ChannelType type) +{ + return adopt(*new BMIDEChannel(ide_controller, io_group, type)); +} + +UNMAP_AFTER_INIT BMIDEChannel::BMIDEChannel(const IDEController& controller, IDEChannel::IOAddressGroup io_group, IDEChannel::ChannelType type) + : IDEChannel(controller, io_group, type) +{ + initialize(); +} + +UNMAP_AFTER_INIT void BMIDEChannel::initialize() +{ + // Let's try to set up DMA transfers. + PCI::enable_bus_mastering(m_parent_controller->pci_address()); + m_prdt_page = MM.allocate_supervisor_physical_page(); + m_dma_buffer_page = MM.allocate_supervisor_physical_page(); + if (m_dma_buffer_page.is_null() || m_prdt_page.is_null()) + return; + m_prdt_region = MM.allocate_kernel_region(m_prdt_page->paddr(), PAGE_SIZE, "IDE PRDT", Region::Access::Read | Region::Access::Write); + m_dma_buffer_region = MM.allocate_kernel_region(m_dma_buffer_page->paddr(), PAGE_SIZE, "IDE DMA region", Region::Access::Read | Region::Access::Write); + prdt().end_of_table = 0x8000; +} + +static void print_ide_status(u8 status) +{ + dbgln("BMIDEChannel: print_ide_status: DRQ={} BSY={}, DRDY={}, DSC={}, DF={}, CORR={}, IDX={}, ERR={}", + (status & ATA_SR_DRQ) != 0, + (status & ATA_SR_BSY) != 0, + (status & ATA_SR_DRDY) != 0, + (status & ATA_SR_DSC) != 0, + (status & ATA_SR_DF) != 0, + (status & ATA_SR_CORR) != 0, + (status & ATA_SR_IDX) != 0, + (status & ATA_SR_ERR) != 0); +} + +void BMIDEChannel::handle_irq(const RegisterState&) +{ + u8 status = m_io_group.io_base().offset(ATA_REG_STATUS).in(); + + m_entropy_source.add_random_event(status); + + u8 bstatus = m_io_group.bus_master_base().offset(2).in(); + if (!(bstatus & 0x4)) { + // interrupt not from this device, ignore + dbgln_if(PATA_DEBUG, "BMIDEChannel: ignore interrupt"); + return; + } + + ScopedSpinLock lock(m_request_lock); + dbgln_if(PATA_DEBUG, "BMIDEChannel: interrupt: DRQ={}, BSY={}, DRDY={}", + (status & ATA_SR_DRQ) != 0, + (status & ATA_SR_BSY) != 0, + (status & ATA_SR_DRDY) != 0); + + if (!m_current_request) { + dbgln("BMIDEChannel: IRQ but no pending request!"); + return; + } + + if (status & ATA_SR_ERR) { + print_ide_status(status); + m_device_error = m_io_group.io_base().offset(ATA_REG_ERROR).in(); + dbgln("BMIDEChannel: Error {:#02x}!", (u8)m_device_error); + try_disambiguate_error(); + complete_current_request(AsyncDeviceRequest::Failure); + return; + } + m_device_error = 0; + complete_current_request(AsyncDeviceRequest::Success); +} + +void BMIDEChannel::complete_current_request(AsyncDeviceRequest::RequestResult result) +{ + // NOTE: this may be called from the interrupt handler! + VERIFY(m_current_request); + VERIFY(m_request_lock.is_locked()); + + // Now schedule reading back the buffer as soon as we leave the irq handler. + // This is important so that we can safely write the buffer back, + // which could cause page faults. Note that this may be called immediately + // before Processor::deferred_call_queue returns! + g_io_work->queue([this, result]() { + dbgln_if(PATA_DEBUG, "BMIDEChannel::complete_current_request result: {}", (int)result); + ScopedSpinLock lock(m_request_lock); + VERIFY(m_current_request); + auto& request = *m_current_request; + m_current_request = nullptr; + + if (result == AsyncDeviceRequest::Success) { + if (request.request_type() == AsyncBlockDeviceRequest::Read) { + if (!request.write_to_buffer(request.buffer(), m_dma_buffer_region->vaddr().as_ptr(), 512 * request.block_count())) { + lock.unlock(); + request.complete(AsyncDeviceRequest::MemoryFault); + return; + } + } + + // I read somewhere that this may trigger a cache flush so let's do it. + m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); + } + + lock.unlock(); + request.complete(result); + }); +} + +void BMIDEChannel::ata_write_sectors(bool slave_request, u16 capabilities) +{ + VERIFY(m_request_lock.is_locked()); + auto& request = *m_current_request; + auto lba = request.block_index(); + dbgln_if(PATA_DEBUG, "BMIDEChannel::ata_write_sectors_with_dma ({} x {})", lba, request.block_count()); + + prdt().offset = m_dma_buffer_page->paddr().get(); + prdt().size = 512 * request.block_count(); + + if (!request.read_from_buffer(request.buffer(), m_dma_buffer_region->vaddr().as_ptr(), 512 * request.block_count())) { + complete_current_request(AsyncDeviceRequest::MemoryFault); + return; + } + + VERIFY(prdt().size <= PAGE_SIZE); + + // Stop bus master + m_io_group.bus_master_base().out(0); + + // Write the PRDT location + m_io_group.bus_master_base().offset(4).out(m_prdt_page->paddr().get()); + + // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. + m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); + + ata_access(Direction::Write, slave_request, lba, request.block_count(), capabilities); + + // Start bus master + m_io_group.bus_master_base().out(0x1); +} + +void BMIDEChannel::send_ata_io_command(LBAMode lba_mode, Direction direction) const +{ + if (lba_mode != LBAMode::FortyEightBit) { + m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_DMA : ATA_CMD_WRITE_DMA); + } else { + m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_DMA_EXT : ATA_CMD_WRITE_DMA_EXT); + } +} + +void BMIDEChannel::ata_read_sectors(bool slave_request, u16 capabilities) +{ + VERIFY(m_request_lock.is_locked()); + auto& request = *m_current_request; + auto lba = request.block_index(); + dbgln_if(PATA_DEBUG, "BMIDEChannel::ata_read_sectors_with_dma ({} x {})", lba, request.block_count()); + + prdt().offset = m_dma_buffer_page->paddr().get(); + prdt().size = 512 * request.block_count(); + + VERIFY(prdt().size <= PAGE_SIZE); + + // Stop bus master + m_io_group.bus_master_base().out(0); + + // Write the PRDT location + m_io_group.bus_master_base().offset(4).out(m_prdt_page->paddr().get()); + + // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. + m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); + + // Set transfer direction + m_io_group.bus_master_base().out(0x8); + + ata_access(Direction::Read, slave_request, lba, request.block_count(), capabilities); + + // Start bus master + m_io_group.bus_master_base().out(0x9); +} + +} diff --git a/Kernel/Storage/BMIDEChannel.h b/Kernel/Storage/BMIDEChannel.h new file mode 100644 index 0000000000..281048f1a0 --- /dev/null +++ b/Kernel/Storage/BMIDEChannel.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace Kernel { + +class AsyncBlockDeviceRequest; + +struct [[gnu::packed]] PhysicalRegionDescriptor { + u32 offset; + u16 size { 0 }; + u16 end_of_table { 0 }; +}; + +class IDEController; +class BMIDEChannel final : public IDEChannel { + friend class IDEController; + friend class PATADiskDevice; + +public: + static NonnullRefPtr create(const IDEController&, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type); + virtual ~BMIDEChannel() override {}; + + virtual bool is_dma_enabled() const override { return true; }; + +private: + BMIDEChannel(const IDEController&, IDEChannel::IOAddressGroup, IDEChannel::ChannelType type); + void initialize(); + + void complete_current_request(AsyncDeviceRequest::RequestResult); + + //^ IRQHandler + virtual void handle_irq(const RegisterState&) override; + + //* IDEChannel + virtual void send_ata_io_command(LBAMode lba_mode, Direction direction) const; + virtual void ata_read_sectors(bool, u16); + virtual void ata_write_sectors(bool, u16); + + PhysicalRegionDescriptor& prdt() { return *reinterpret_cast(m_prdt_region->vaddr().as_ptr()); } + OwnPtr m_prdt_region; + OwnPtr m_dma_buffer_region; + RefPtr m_prdt_page; + RefPtr m_dma_buffer_page; +}; +} diff --git a/Kernel/Storage/IDEChannel.cpp b/Kernel/Storage/IDEChannel.cpp index 2fbc43f286..1fc4b9e36c 100644 --- a/Kernel/Storage/IDEChannel.cpp +++ b/Kernel/Storage/IDEChannel.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -45,9 +44,9 @@ namespace Kernel { #define PCI_Mass_Storage_Class 0x1 #define PCI_IDE_Controller_Subclass 0x1 -UNMAP_AFTER_INIT NonnullRefPtr IDEChannel::create(const IDEController& controller, IOAddressGroup io_group, ChannelType type, bool force_pio) +UNMAP_AFTER_INIT NonnullRefPtr IDEChannel::create(const IDEController& controller, IOAddressGroup io_group, ChannelType type) { - return adopt(*new IDEChannel(controller, io_group, type, force_pio)); + return adopt(*new IDEChannel(controller, io_group, type)); } RefPtr IDEChannel::master_device() const @@ -60,7 +59,7 @@ RefPtr IDEChannel::slave_device() const return m_slave; } -UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddressGroup io_group, ChannelType type, bool force_pio) +UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddressGroup io_group, ChannelType type) : IRQHandler(type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ) , m_channel_type(type) , m_io_group(io_group) @@ -69,15 +68,16 @@ UNMAP_AFTER_INIT IDEChannel::IDEChannel(const IDEController& controller, IOAddre disable_irq(); // FIXME: The device may not be capable of DMA. - m_dma_enabled.resource() = !force_pio; - ProcFS::add_sys_bool("ide_dma", m_dma_enabled); - initialize(force_pio); + dbgln_if(PATA_DEBUG, "IDEChannel: {} IO base: {}", channel_type_string(), m_io_group.io_base()); + dbgln_if(PATA_DEBUG, "IDEChannel: {} control base: {}", channel_type_string(), m_io_group.control_base()); + dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base: {}", channel_type_string(), m_io_group.bus_master_base()); + m_parent_controller->enable_pin_based_interrupts(); + detect_disks(); // Note: calling to detect_disks could generate an interrupt, clear it if that's the case clear_pending_interrupts(); - enable_irq(); } void IDEChannel::clear_pending_interrupts() const @@ -89,7 +89,7 @@ UNMAP_AFTER_INIT IDEChannel::~IDEChannel() { } -void IDEChannel::start_request(AsyncBlockDeviceRequest& request, bool use_dma, bool is_slave, u16 capabilities) +void IDEChannel::start_request(AsyncBlockDeviceRequest& request, bool is_slave, u16 capabilities) { ScopedSpinLock lock(m_request_lock); @@ -97,20 +97,12 @@ void IDEChannel::start_request(AsyncBlockDeviceRequest& request, bool use_dma, b m_current_request = &request; m_current_request_block_index = 0; - m_current_request_uses_dma = use_dma; m_current_request_flushing_cache = false; - if (request.request_type() == AsyncBlockDeviceRequest::Read) { - if (use_dma) - ata_read_sectors_with_dma(is_slave, capabilities); - else - ata_read_sectors(is_slave, capabilities); - } else { - if (use_dma) - ata_write_sectors_with_dma(is_slave, capabilities); - else - ata_write_sectors(is_slave, capabilities); - } + if (request.request_type() == AsyncBlockDeviceRequest::Read) + ata_read_sectors(is_slave, capabilities); + else + ata_write_sectors(is_slave, capabilities); } void IDEChannel::complete_current_request(AsyncDeviceRequest::RequestResult result) @@ -130,46 +122,11 @@ void IDEChannel::complete_current_request(AsyncDeviceRequest::RequestResult resu auto& request = *m_current_request; m_current_request = nullptr; - if (m_current_request_uses_dma) { - if (result == AsyncDeviceRequest::Success) { - if (request.request_type() == AsyncBlockDeviceRequest::Read) { - if (!request.write_to_buffer(request.buffer(), m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * request.block_count())) { - lock.unlock(); - request.complete(AsyncDeviceRequest::MemoryFault); - return; - } - } - - // I read somewhere that this may trigger a cache flush so let's do it. - m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); - } - } - lock.unlock(); request.complete(result); }); } -UNMAP_AFTER_INIT void IDEChannel::initialize(bool force_pio) -{ - m_parent_controller->enable_pin_based_interrupts(); - - dbgln_if(PATA_DEBUG, "IDEChannel: {} IO base: {}", channel_type_string(), m_io_group.io_base()); - dbgln_if(PATA_DEBUG, "IDEChannel: {} control base: {}", channel_type_string(), m_io_group.control_base()); - dbgln_if(PATA_DEBUG, "IDEChannel: {} bus master base: {}", channel_type_string(), m_io_group.bus_master_base()); - - if (force_pio) { - dbgln("IDEChannel: Requested to force PIO mode; not setting up DMA"); - return; - } - - // Let's try to set up DMA transfers. - PCI::enable_bus_mastering(m_parent_controller->pci_address()); - m_prdt_page = MM.allocate_supervisor_physical_page(); - prdt().end_of_table = 0x8000; - m_dma_buffer_page = MM.allocate_supervisor_physical_page(); -} - static void print_ide_status(u8 status) { dbgln("IDEChannel: print_ide_status: DRQ={} BSY={}, DRDY={}, DSC={}, DF={}, CORR={}, IDX={}, ERR={}", @@ -251,10 +208,6 @@ void IDEChannel::handle_irq(const RegisterState&) return; } m_device_error = 0; - if (m_current_request_uses_dma) { - complete_current_request(AsyncDeviceRequest::Success); - return; - } // Now schedule reading/writing the buffer as soon as we leave the irq handler. // This is important so that we can safely access the buffers, which could @@ -404,7 +357,7 @@ UNMAP_AFTER_INIT void IDEChannel::detect_disks() } } -void IDEChannel::ata_access(Direction direction, bool slave_request, u64 lba, u8 block_count, u16 capabilities, bool use_dma) +void IDEChannel::ata_access(Direction direction, bool slave_request, u64 lba, u8 block_count, u16 capabilities) { LBAMode lba_mode; u8 head = 0; @@ -439,48 +392,17 @@ void IDEChannel::ata_access(Direction direction, bool slave_request, u64 lba, u8 if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; } - - if (lba_mode != LBAMode::FortyEightBit) { - if (use_dma) - m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_DMA : ATA_CMD_WRITE_DMA); - else - m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_PIO : ATA_CMD_WRITE_PIO); - } else { - if (use_dma) - m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_DMA_EXT : ATA_CMD_WRITE_DMA_EXT); - else - m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_PIO_EXT : ATA_CMD_WRITE_PIO_EXT); - } + send_ata_io_command(lba_mode, direction); enable_irq(); } -void IDEChannel::ata_read_sectors_with_dma(bool slave_request, u16 capabilities) +void IDEChannel::send_ata_io_command(LBAMode lba_mode, Direction direction) const { - auto& request = *m_current_request; - auto lba = request.block_index(); - dbgln_if(PATA_DEBUG, "IDEChannel::ata_read_sectors_with_dma ({} x {})", lba, request.block_count()); - - prdt().offset = m_dma_buffer_page->paddr(); - prdt().size = 512 * request.block_count(); - - VERIFY(prdt().size <= PAGE_SIZE); - - // Stop bus master - m_io_group.bus_master_base().out(0); - - // Write the PRDT location - m_io_group.bus_master_base().offset(4).out(m_prdt_page->paddr().get()); - - // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. - m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); - - // Set transfer direction - m_io_group.bus_master_base().out(0x8); - - ata_access(Direction::Read, slave_request, lba, request.block_count(), capabilities, true); - - // Start bus master - m_io_group.bus_master_base().out(0x9); + if (lba_mode != LBAMode::FortyEightBit) { + m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_PIO : ATA_CMD_WRITE_PIO); + } else { + m_io_group.io_base().offset(ATA_REG_COMMAND).out(direction == Direction::Read ? ATA_CMD_READ_PIO_EXT : ATA_CMD_WRITE_PIO_EXT); + } } bool IDEChannel::ata_do_read_sector() @@ -511,38 +433,7 @@ void IDEChannel::ata_read_sectors(bool slave_request, u16 capabilities) auto lba = request.block_index(); dbgln_if(PATA_DEBUG, "IDEChannel: Reading {} sector(s) @ LBA {}", request.block_count(), lba); - ata_access(Direction::Read, slave_request, lba, request.block_count(), capabilities, false); -} - -void IDEChannel::ata_write_sectors_with_dma(bool slave_request, u16 capabilities) -{ - auto& request = *m_current_request; - auto lba = request.block_index(); - dbgln_if(PATA_DEBUG, "IDEChannel::ata_write_sectors_with_dma ({} x {})", lba, request.block_count()); - - prdt().offset = m_dma_buffer_page->paddr(); - prdt().size = 512 * request.block_count(); - - if (!request.read_from_buffer(request.buffer(), m_dma_buffer_page->paddr().offset(0xc0000000).as_ptr(), 512 * request.block_count())) { - complete_current_request(AsyncDeviceRequest::MemoryFault); - return; - } - - VERIFY(prdt().size <= PAGE_SIZE); - - // Stop bus master - m_io_group.bus_master_base().out(0); - - // Write the PRDT location - m_io_group.bus_master_base().offset(4).out(m_prdt_page->paddr().get()); - - // Turn on "Interrupt" and "Error" flag. The error flag should be cleared by hardware. - m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); - - ata_access(Direction::Write, slave_request, lba, request.block_count(), capabilities, true); - - // Start bus master - m_io_group.bus_master_base().out(0x1); + ata_access(Direction::Read, slave_request, lba, request.block_count(), capabilities); } void IDEChannel::ata_do_write_sector() @@ -577,7 +468,7 @@ void IDEChannel::ata_write_sectors(bool slave_request, u16 capabilities) u32 count = request.block_count(); dbgln_if(PATA_DEBUG, "IDEChannel: Writing {} sector(s) @ LBA {}", count, start_sector); - ata_access(Direction::Write, slave_request, start_sector, request.block_count(), capabilities, false); + ata_access(Direction::Write, slave_request, start_sector, request.block_count(), capabilities); ata_do_write_sector(); } } diff --git a/Kernel/Storage/IDEChannel.h b/Kernel/Storage/IDEChannel.h index 095bc3808f..192c149a80 100644 --- a/Kernel/Storage/IDEChannel.h +++ b/Kernel/Storage/IDEChannel.h @@ -37,7 +37,6 @@ #pragma once -#include #include #include #include @@ -53,14 +52,8 @@ namespace Kernel { class AsyncBlockDeviceRequest; -struct PhysicalRegionDescriptor { - PhysicalAddress offset; - u16 size { 0 }; - u16 end_of_table { 0 }; -}; - class IDEController; -class IDEChannel final : public RefCounted +class IDEChannel : public RefCounted , public IRQHandler { friend class IDEController; friend class PATADiskDevice; @@ -105,7 +98,7 @@ public: }; public: - static NonnullRefPtr create(const IDEController&, IOAddressGroup, ChannelType type, bool force_pio); + static NonnullRefPtr create(const IDEController&, IOAddressGroup, ChannelType type); virtual ~IDEChannel() override; RefPtr master_device() const; @@ -113,12 +106,12 @@ public: virtual const char* purpose() const override { return "PATA Channel"; } + virtual bool is_dma_enabled() const { return false; } + private: - IDEChannel(const IDEController&, IOAddressGroup, ChannelType type, bool force_pio); - - //^ IRQHandler - virtual void handle_irq(const RegisterState&) override; + void complete_current_request(AsyncDeviceRequest::RequestResult); +protected: enum class LBAMode : u8 { None, // CHS TwentyEightBit, @@ -130,35 +123,34 @@ private: Write, }; - void initialize(bool force_pio); + IDEChannel(const IDEController&, IOAddressGroup, ChannelType type); + //^ IRQHandler + virtual void handle_irq(const RegisterState&) override; + + virtual void send_ata_io_command(LBAMode lba_mode, Direction direction) const; + + virtual void ata_read_sectors(bool, u16); + virtual void ata_write_sectors(bool, u16); + void detect_disks(); String channel_type_string() const; void try_disambiguate_error(); void wait_until_not_busy(); - void start_request(AsyncBlockDeviceRequest&, bool, bool, u16); - void complete_current_request(AsyncDeviceRequest::RequestResult); + void start_request(AsyncBlockDeviceRequest&, bool, u16); void clear_pending_interrupts() const; - void ata_access(Direction, bool, u64, u8, u16, bool); - void ata_read_sectors_with_dma(bool, u16); - void ata_read_sectors(bool, u16); + void ata_access(Direction, bool, u64, u8, u16); + bool ata_do_read_sector(); - void ata_write_sectors_with_dma(bool, u16); - void ata_write_sectors(bool, u16); void ata_do_write_sector(); // Data members ChannelType m_channel_type { ChannelType::Primary }; volatile u8 m_device_error { 0 }; - - PhysicalRegionDescriptor& prdt() { return *reinterpret_cast(m_prdt_page->paddr().offset(0xc0000000).as_ptr()); } - RefPtr m_prdt_page; - RefPtr m_dma_buffer_page; - Lockable m_dma_enabled; EntropySource m_entropy_source; RefPtr m_master; @@ -166,7 +158,6 @@ private: AsyncBlockDeviceRequest* m_current_request { nullptr }; u32 m_current_request_block_index { 0 }; - bool m_current_request_uses_dma { false }; bool m_current_request_flushing_cache { false }; SpinLock m_request_lock; diff --git a/Kernel/Storage/IDEController.cpp b/Kernel/Storage/IDEController.cpp index ff46722c5a..56a83b2f5c 100644 --- a/Kernel/Storage/IDEController.cpp +++ b/Kernel/Storage/IDEController.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -87,13 +89,21 @@ UNMAP_AFTER_INIT void IDEController::initialize(bool force_pio) auto bar1 = PCI::get_BAR1(pci_address()); auto control_io = (bar1 == 0x1 || bar1 == 0) ? IOAddress(0x3F6) : IOAddress(bar1); - m_channels.append(IDEChannel::create(*this, { base_io, control_io, bus_master_base }, IDEChannel::ChannelType::Primary, force_pio)); + if (force_pio) + m_channels.append(IDEChannel::create(*this, { base_io, control_io, bus_master_base }, IDEChannel::ChannelType::Primary)); + else + m_channels.append(BMIDEChannel::create(*this, { base_io, control_io, bus_master_base }, IDEChannel::ChannelType::Primary)); + m_channels[0].enable_irq(); auto bar2 = PCI::get_BAR2(pci_address()); base_io = (bar2 == 0x1 || bar2 == 0) ? IOAddress(0x170) : IOAddress(bar2); auto bar3 = PCI::get_BAR3(pci_address()); control_io = (bar3 == 0x1 || bar3 == 0) ? IOAddress(0x376) : IOAddress(bar3); - m_channels.append(IDEChannel::create(*this, { base_io, control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary, force_pio)); + if (force_pio) + m_channels.append(IDEChannel::create(*this, { base_io, control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary)); + else + m_channels.append(BMIDEChannel::create(*this, { base_io, control_io, bus_master_base.offset(8) }, IDEChannel::ChannelType::Secondary)); + m_channels[1].enable_irq(); } RefPtr IDEController::device_by_channel_and_position(u32 index) const diff --git a/Kernel/Storage/PATADiskDevice.cpp b/Kernel/Storage/PATADiskDevice.cpp index 1e6b6cba29..d75baf5311 100644 --- a/Kernel/Storage/PATADiskDevice.cpp +++ b/Kernel/Storage/PATADiskDevice.cpp @@ -58,8 +58,7 @@ const char* PATADiskDevice::class_name() const void PATADiskDevice::start_request(AsyncBlockDeviceRequest& request) { - bool use_dma = !m_channel->m_io_group.bus_master_base().is_null() && m_channel->m_dma_enabled.resource(); - m_channel->start_request(request, use_dma, is_slave(), m_capabilities); + m_channel->start_request(request, is_slave(), m_capabilities); } String PATADiskDevice::device_name() const