summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-05-19 04:40:30 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-05-19 04:40:30 +0200
commitc7d8aa6969c2d30f1209be0c95b1bfc31c79831f (patch)
tree675cd69405d34354e6e8181bad164452d36949bf /Kernel
parented79116e9469beb8cad66ea98fcc2e0198485d36 (diff)
downloadserenity-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.cpp8
-rw-r--r--Kernel/Devices/DiskDevice.h2
-rw-r--r--Kernel/Devices/IDEDiskDevice.cpp27
-rw-r--r--Kernel/Devices/IDEDiskDevice.h4
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 };
};