From ab90d2e251a8677fae87d8b166b7ce9b02f52d29 Mon Sep 17 00:00:00 2001 From: Jesse Date: Mon, 8 Jul 2019 06:16:52 +0000 Subject: [PATCH] Kernel: Extended IDE interface to allow slave device usage (#283) The IDE Disk Controller driver has been extended to allow the secondary device on the channel to be initialised and used. A test as to whether this is working (for anyone interested) is to modify `init.cpp:87` to `auto dev_hd0 = IDEDiskDevice::create(IdeDiskDevice::DeviceType::SLAVE);`. The kernel will fail to boot, as there is no disk attached to CHANNEL 1's slave. This was born out of the fact that my FAT driver can't be tested as easily without creating a partition on `hda`. --- Kernel/Devices/IDEDiskDevice.cpp | 45 +++++++++++++++++++++++++------- Kernel/Devices/IDEDiskDevice.h | 18 +++++++++++-- Kernel/init.cpp | 2 +- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/Kernel/Devices/IDEDiskDevice.cpp b/Kernel/Devices/IDEDiskDevice.cpp index 186e6f1742..78bcba7ced 100644 --- a/Kernel/Devices/IDEDiskDevice.cpp +++ b/Kernel/Devices/IDEDiskDevice.cpp @@ -78,14 +78,15 @@ #define ATA_REG_ALTSTATUS 0x0C #define ATA_REG_DEVADDRESS 0x0D -NonnullRefPtr IDEDiskDevice::create() +NonnullRefPtr IDEDiskDevice::create(DriveType type) { - return adopt(*new IDEDiskDevice); + return adopt(*new IDEDiskDevice(type)); } -IDEDiskDevice::IDEDiskDevice() +IDEDiskDevice::IDEDiskDevice(DriveType type) : IRQHandler(IRQ_FIXED_DISK) , m_io_base(0x1f0) + , m_drive_type(type) { m_dma_enabled.resource() = true; ProcFS::the().add_sys_bool("ide_dma", m_dma_enabled); @@ -195,6 +196,9 @@ void IDEDiskDevice::initialize() u8 status = IO::in8(m_io_base + ATA_REG_STATUS); kprintf("initial status: "); print_ide_status(status); + + if (is_slave()) + kprintf("This IDE device is the SECONDARY device on the channel!\n"); #endif m_interrupted = false; @@ -204,8 +208,12 @@ void IDEDiskDevice::initialize() enable_irq(); - IO::out8(0x1F6, 0xA0); // 0xB0 for 2nd device - IO::out8(0x3F6, 0xA0); // 0xB0 for 2nd device + u8 devsel = 0xA0; + if (is_slave()) + devsel |= 0x10; + + IO::out8(0x1F6, devsel); + IO::out8(0x3F6, devsel); IO::out8(m_io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); enable_irq(); @@ -290,9 +298,12 @@ bool IDEDiskDevice::read_sectors_with_dma(u32 lba, u16 count, u8* outbuf) ; bool is_slave = false; + u8 devsel = 0xe0; + if (is_slave()) + devsel |= 0x10; IO::out8(m_io_base + ATA_REG_CONTROL, 0); - IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | (is_slave << 4)); + IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | (is_slave << 4)); wait_400ns(m_io_base); IO::out8(m_io_base + ATA_REG_FEATURES, 0); @@ -351,11 +362,15 @@ bool IDEDiskDevice::read_sectors(u32 start_sector, u16 count, u8* outbuf) kprintf("IDEDiskDevice: Reading %u sector(s) @ LBA %u\n", count, start_sector); #endif + u8 devsel = 0xe0; + if (is_slave()) + devsel |= 0x10; + IO::out8(m_io_base + ATA_REG_SECCOUNT0, count == 256 ? 0 : LSB(count)); IO::out8(m_io_base + ATA_REG_LBA0, start_sector & 0xff); IO::out8(m_io_base + ATA_REG_LBA1, (start_sector >> 8) & 0xff); IO::out8(m_io_base + ATA_REG_LBA2, (start_sector >> 16) & 0xff); - IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | ((start_sector >> 24) & 0xf)); // 0xf0 for 2nd device + IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | ((start_sector >> 24) & 0xf)); IO::out8(0x3F6, 0x08); while (!(IO::in8(m_io_base + ATA_REG_STATUS) & ATA_SR_DRDY)) @@ -413,9 +428,12 @@ bool IDEDiskDevice::write_sectors_with_dma(u32 lba, u16 count, const u8* inbuf) ; bool is_slave = false; + u8 devsel = 0xe0; + if (is_slave()) + devsel |= 0x10; IO::out8(m_io_base + ATA_REG_CONTROL, 0); - IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | (is_slave << 4)); + IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | (is_slave << 4)); wait_400ns(m_io_base); IO::out8(m_io_base + ATA_REG_FEATURES, 0); @@ -471,11 +489,15 @@ bool IDEDiskDevice::write_sectors(u32 start_sector, u16 count, const u8* data) //dbgprintf("IDEDiskDevice: Writing %u sector(s) @ LBA %u\n", count, start_sector); + u8 devsel = 0xe0; + if (is_slave()) + devsel |= 0x10; + IO::out8(m_io_base + ATA_REG_SECCOUNT0, count == 256 ? 0 : LSB(count)); IO::out8(m_io_base + ATA_REG_LBA0, start_sector & 0xff); IO::out8(m_io_base + ATA_REG_LBA1, (start_sector >> 8) & 0xff); IO::out8(m_io_base + ATA_REG_LBA2, (start_sector >> 16) & 0xff); - IO::out8(m_io_base + ATA_REG_HDDEVSEL, 0xe0 | ((start_sector >> 24) & 0xf)); // 0xf0 for 2nd device + IO::out8(m_io_base + ATA_REG_HDDEVSEL, devsel | ((start_sector >> 24) & 0xf)); IO::out8(0x3F6, 0x08); @@ -502,3 +524,8 @@ bool IDEDiskDevice::write_sectors(u32 start_sector, u16 count, const u8* data) return !m_device_error; } + +bool IDEDiskDevice::is_slave() const +{ + return m_drive_type == DriveType::SLAVE; +} diff --git a/Kernel/Devices/IDEDiskDevice.h b/Kernel/Devices/IDEDiskDevice.h index 23a3b53fbb..e9f3d2f5e9 100644 --- a/Kernel/Devices/IDEDiskDevice.h +++ b/Kernel/Devices/IDEDiskDevice.h @@ -18,7 +18,18 @@ class IDEDiskDevice final : public IRQHandler , public DiskDevice { AK_MAKE_ETERNAL public: - static NonnullRefPtr create(); + + // Type of drive this IDEDiskDevice is on the ATA channel. + // + // Each PATA channel can contain only two devices, which (I think) are + // jumper selectable on the drive itself by shorting two pins. + enum class DriveType : u8 { + MASTER, + SLAVE + }; + +public: + static NonnullRefPtr create(DriveType type); virtual ~IDEDiskDevice() override; // ^DiskDevice @@ -29,7 +40,7 @@ public: virtual bool write_blocks(unsigned index, u16 count, const u8*) override; protected: - IDEDiskDevice(); + explicit IDEDiskDevice(DriveType); private: // ^IRQHandler @@ -45,6 +56,8 @@ private: bool read_sectors(u32 lba, u16 count, u8* buffer); bool write_sectors(u32 lba, u16 count, const u8* data); + bool is_slave() const; + Lock m_lock { "IDEDiskDevice" }; u16 m_cylinders { 0 }; u16 m_heads { 0 }; @@ -53,6 +66,7 @@ private: volatile bool m_interrupted { false }; volatile u8 m_device_error { 0 }; + DriveType m_drive_type { DriveType::MASTER }; PCI::Address m_pci_address; PhysicalRegionDescriptor m_prdt; RefPtr m_dma_buffer_page; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index d2bc73e870..48b9b0815a 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -84,7 +84,7 @@ VFS* vfs; hang(); } - auto dev_hd0 = IDEDiskDevice::create(); + auto dev_hd0 = IDEDiskDevice::create(IDEDiskDevice::DriveType::MASTER); NonnullRefPtr root_dev = dev_hd0.copy_ref();