diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-05-19 04:40:30 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-05-19 04:40:30 +0200 |
commit | c7d8aa6969c2d30f1209be0c95b1bfc31c79831f (patch) | |
tree | 675cd69405d34354e6e8181bad164452d36949bf /Kernel | |
parent | ed79116e9469beb8cad66ea98fcc2e0198485d36 (diff) | |
download | serenity-c7d8aa6969c2d30f1209be0c95b1bfc31c79831f.zip |
IDEDiskDevice: Support reading multiple sectors at a time with DMA.
This is another sizable improvement to GCC compile times.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Devices/DiskDevice.cpp | 8 | ||||
-rw-r--r-- | Kernel/Devices/DiskDevice.h | 2 | ||||
-rw-r--r-- | Kernel/Devices/IDEDiskDevice.cpp | 27 | ||||
-rw-r--r-- | Kernel/Devices/IDEDiskDevice.h | 4 |
4 files changed, 27 insertions, 14 deletions
diff --git a/Kernel/Devices/DiskDevice.cpp b/Kernel/Devices/DiskDevice.cpp index 3c2b210641..1298455efe 100644 --- a/Kernel/Devices/DiskDevice.cpp +++ b/Kernel/Devices/DiskDevice.cpp @@ -15,12 +15,8 @@ bool DiskDevice::read(DiskOffset offset, unsigned length, byte* out) const dword first_block = offset / block_size(); dword end_block = (offset + length) / block_size(); byte* outptr = out; - for (unsigned bi = first_block; bi < end_block; ++bi) { - if (!read_block(bi, outptr)) - return false; - outptr += block_size(); - } - return true; + + return const_cast<DiskDevice*>(this)->read_blocks(first_block, end_block - first_block, outptr); } bool DiskDevice::write(DiskOffset offset, unsigned length, const byte* in) diff --git a/Kernel/Devices/DiskDevice.h b/Kernel/Devices/DiskDevice.h index 071c5cd63b..cbccc1c65b 100644 --- a/Kernel/Devices/DiskDevice.h +++ b/Kernel/Devices/DiskDevice.h @@ -17,6 +17,8 @@ public: bool read(DiskOffset, unsigned length, byte*) const; bool write(DiskOffset, unsigned length, const byte*); + virtual bool read_blocks(unsigned index, word count, byte*) = 0; + protected: DiskDevice(); }; diff --git a/Kernel/Devices/IDEDiskDevice.cpp b/Kernel/Devices/IDEDiskDevice.cpp index 3c234fa6b8..10e928b9bf 100644 --- a/Kernel/Devices/IDEDiskDevice.cpp +++ b/Kernel/Devices/IDEDiskDevice.cpp @@ -6,6 +6,7 @@ #include "Scheduler.h" #include "PIC.h" #include <Kernel/Lock.h> +#include <Kernel/VM/MemoryManager.h> //#define DISK_DEBUG @@ -126,10 +127,17 @@ unsigned IDEDiskDevice::block_size() const return 512; } +bool IDEDiskDevice::read_blocks(unsigned index, word count, byte* out) +{ + if (m_bus_master_base) + return read_sectors_with_dma(index, count, out); + return read_sectors(index, count, out); +} + bool IDEDiskDevice::read_block(unsigned index, byte* out) const { if (m_bus_master_base) - return const_cast<IDEDiskDevice&>(*this).read_sector_with_dma(index, out); + return const_cast<IDEDiskDevice&>(*this).read_sectors_with_dma(index, 1, out); return const_cast<IDEDiskDevice&>(*this).read_sectors(index, 1, out); } @@ -248,6 +256,7 @@ void IDEDiskDevice::initialize() m_prdt.end_of_table = 0x8000; PCI::enable_bus_mastering(m_pci_address); m_bus_master_base = PCI::get_BAR4(m_pci_address) & 0xfffc; + m_dma_buffer_page = MM.allocate_supervisor_physical_page(); dbgprintf("PIIX Bus master IDE: I/O @ %x\n", m_bus_master_base); } } @@ -258,19 +267,21 @@ static void wait_400ns(word io_base) IO::in8(io_base + ATA_REG_ALTSTATUS); } -bool IDEDiskDevice::read_sector_with_dma(dword lba, byte* outbuf) +bool IDEDiskDevice::read_sectors_with_dma(dword lba, word count, byte* outbuf) { LOCKER(m_lock); #ifdef DISK_DEBUG - dbgprintf("%s(%u): IDEDiskDevice::read_sector_with_dma (%u) -> %p\n", + dbgprintf("%s(%u): IDEDiskDevice::read_sectors_with_dma (%u x%u) -> %p\n", current->process().name().characters(), - current->pid(), lba, outbuf); + current->pid(), lba, count, outbuf); #endif disable_irq(); - m_prdt.offset = PhysicalAddress((dword)outbuf); - m_prdt.size = 512; + m_prdt.offset = m_dma_buffer_page->paddr(); + m_prdt.size = 512 * count; + + ASSERT(m_prdt.size <= PAGE_SIZE); // Stop bus master IO::out8(m_bus_master_base, 0); @@ -303,7 +314,7 @@ bool IDEDiskDevice::read_sector_with_dma(dword lba, byte* outbuf) IO::out8(io_base + ATA_REG_LBA1, 0); IO::out8(io_base + ATA_REG_LBA2, 0); - IO::out8(io_base + ATA_REG_SECCOUNT0, 1); + IO::out8(io_base + ATA_REG_SECCOUNT0, count); IO::out8(io_base + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); IO::out8(io_base + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); IO::out8(io_base + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); @@ -326,6 +337,8 @@ bool IDEDiskDevice::read_sector_with_dma(dword lba, byte* outbuf) if (m_device_error) return false; + memcpy(outbuf, m_dma_buffer_page->paddr().as_ptr(), 512 * count); + // I read somewhere that this may trigger a cache flush so let's do it. IO::out8(m_bus_master_base + 2, IO::in8(m_bus_master_base + 2) | 0x6); return true; diff --git a/Kernel/Devices/IDEDiskDevice.h b/Kernel/Devices/IDEDiskDevice.h index c5dbdacd68..4a8e497926 100644 --- a/Kernel/Devices/IDEDiskDevice.h +++ b/Kernel/Devices/IDEDiskDevice.h @@ -24,6 +24,7 @@ public: virtual unsigned block_size() const override; virtual bool read_block(unsigned index, byte*) const override; virtual bool write_block(unsigned index, const byte*) override; + virtual bool read_blocks(unsigned index, word count, byte*) override; protected: IDEDiskDevice(); @@ -37,7 +38,7 @@ private: void initialize(); bool wait_for_irq(); - bool read_sector_with_dma(dword sector, byte*); + bool read_sectors_with_dma(dword sector, word count, byte*); bool read_sectors(dword start_sector, word count, byte* buffer); bool write_sectors(dword start_sector, word count, const byte* data); @@ -50,6 +51,7 @@ private: PCI::Address m_pci_address; PhysicalRegionDescriptor m_prdt; + RetainPtr<PhysicalPage> m_dma_buffer_page; word m_bus_master_base { 0 }; }; |