From 0a2b00a1bf6fa1eb23fbf95a6759c8fc16d24b81 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 19 Dec 2020 12:50:57 +0200 Subject: [PATCH] Kernel: Introduce the new Storage subsystem This new subsystem is somewhat replacing the IDE disk code we had with a new flexible design. StorageDevice is a generic class that represent a generic storage device. It is meant that specific storage hardware will override the interface. StorageController is a generic class that represent a storage controller that can be found in a machine. The IDEController class governs two IDEChannels. An IDEChannel is responsible to manage the master & slave devices of the channel, therefore an IDEChannel is an IRQHandler. --- CMakeLists.txt | 2 +- Kernel/CMakeLists.txt | 6 +- .../IDEChannel.cpp} | 267 +++++++++--------- .../PATAChannel.h => Storage/IDEChannel.h} | 65 ++++- Kernel/Storage/IDEController.cpp | 103 +++++++ Kernel/Storage/IDEController.h | 61 ++++ Kernel/Storage/PATADiskDevice.cpp | 78 +++++ Kernel/{Devices => Storage}/PATADiskDevice.h | 25 +- Kernel/Storage/StorageController.h | 64 +++++ .../StorageDevice.cpp} | 65 ++--- Kernel/Storage/StorageDevice.h | 66 +++++ Kernel/init.cpp | 15 +- 12 files changed, 604 insertions(+), 213 deletions(-) rename Kernel/{Devices/PATAChannel.cpp => Storage/IDEChannel.cpp} (55%) rename Kernel/{Devices/PATAChannel.h => Storage/IDEChannel.h} (65%) create mode 100644 Kernel/Storage/IDEController.cpp create mode 100644 Kernel/Storage/IDEController.h create mode 100644 Kernel/Storage/PATADiskDevice.cpp rename Kernel/{Devices => Storage}/PATADiskDevice.h (76%) create mode 100644 Kernel/Storage/StorageController.h rename Kernel/{Devices/PATADiskDevice.cpp => Storage/StorageDevice.cpp} (78%) create mode 100644 Kernel/Storage/StorageDevice.h diff --git a/CMakeLists.txt b/CMakeLists.txt index db3461d10ad..7998a0c7ed2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,7 @@ if (ALL_THE_DEBUG_MACROS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOBJECT_DEBUG -DOCCLUSIONS_DEBUG -DOFFD_DEBUG") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPAGE_FAULT_DEBUG -DPARSER_DEBUG -DPATA_DEBUG -DPATA_DEVICE_DEBUG -DPATH_DEBUG -DPCI_DEBUG -DPNG_DEBUG -DPPM_DEBUG -DPROCESS_DEBUG -DPROCFS_DEBUG -DPS2MOUSE_DEBUG -DPTHREAD_DEBUG -DPTMX_DEBUG") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DREACHABLE_DEBUG -DREGEX_DEBUG -DRESIZE_DEBUG -DRESOURCE_DEBUG -DROUTING_DEBUG -DRTL8139_DEBUG") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSAFE_SYSCALL_DEBUG -DSB16_DEBUG -DSCHEDULER_DEBUG -DSCHEDULER_RUNNABLE_DEBUG -DSELECTION_DEBUG -DSERVICE_DEBUG -DSHARED_BUFFER_DEBUG -DSH_DEBUG -DSIGNAL_DEBUG -DSLAVEPTY_DEBUG -DSMP_DEBUG -DSOCKET_DEBUG -DSYSTEM_MENU_DEBUG -DSYSTEMSERVER_DEBUG") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSAFE_SYSCALL_DEBUG -DSB16_DEBUG -DSCHEDULER_DEBUG -DSCHEDULER_RUNNABLE_DEBUG -DSELECTION_DEBUG -DSERVICE_DEBUG -DSHARED_BUFFER_DEBUG -DSH_DEBUG -DSIGNAL_DEBUG -DSLAVEPTY_DEBUG -DSMP_DEBUG -DSOCKET_DEBUG -DSYSTEM_MENU_DEBUG -DSYSTEMSERVER_DEBUG -DSTORAGE_DEVICE_DEBUG") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTCP_DEBUG -DTCP_SOCKET_DEBUG -DTERMCAP_DEBUG -DTERMINAL_DEBUG -DTHREAD_DEBUG -DTLS_DEBUG -DTTY_DEBUG") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUCI_DEBUG -DUDP_DEBUG -DUPDATE_COALESCING_DEBUG") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVERY_DEBUG -DVFS_DEBUG -DVMWAREBACKDOOR_DEBUG -DVRA_DEBUG") diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 1bd5adafad8..cae5f5dec26 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -31,8 +31,6 @@ set(KERNEL_SOURCES Devices/MBRPartitionTable.cpp Devices/MBVGADevice.cpp Devices/NullDevice.cpp - Devices/PATAChannel.cpp - Devices/PATADiskDevice.cpp Devices/PCSpeaker.cpp Devices/PS2MouseDevice.cpp Devices/RandomDevice.cpp @@ -41,6 +39,10 @@ set(KERNEL_SOURCES Devices/UHCIController.cpp Devices/VMWareBackdoor.cpp Devices/ZeroDevice.cpp + Storage/StorageDevice.cpp + Storage/IDEController.cpp + Storage/IDEChannel.cpp + Storage/PATADiskDevice.cpp DoubleBuffer.cpp FileSystem/BlockBasedFileSystem.cpp FileSystem/Custody.cpp diff --git a/Kernel/Devices/PATAChannel.cpp b/Kernel/Storage/IDEChannel.cpp similarity index 55% rename from Kernel/Devices/PATAChannel.cpp rename to Kernel/Storage/IDEChannel.cpp index fc3c8057bad..3a2aa3eb737 100644 --- a/Kernel/Devices/PATAChannel.cpp +++ b/Kernel/Storage/IDEChannel.cpp @@ -27,11 +27,12 @@ #include #include #include -#include -#include #include #include #include +#include +#include +#include #include namespace Kernel { @@ -108,24 +109,25 @@ namespace Kernel { #define PCI_Mass_Storage_Class 0x1 #define PCI_IDE_Controller_Subclass 0x1 -OwnPtr PATAChannel::create(ChannelType type, bool force_pio) +NonnullOwnPtr IDEChannel::create(const IDEController& controller, IOAddressGroup io_group, ChannelType type, bool force_pio) { - PCI::Address pci_address; - PCI::enumerate([&](const PCI::Address& address, PCI::ID id) { - if (PCI::get_class(address) == PCI_Mass_Storage_Class && PCI::get_subclass(address) == PCI_IDE_Controller_Subclass) { - pci_address = address; - klog() << "PATAChannel: PATA Controller found, ID " << id; - } - }); - return make(pci_address, type, force_pio); + return make(controller, io_group, type, force_pio); } -PATAChannel::PATAChannel(PCI::Address address, ChannelType type, bool force_pio) - : PCI::Device(address, (type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ)) +RefPtr IDEChannel::master_device() +{ + return m_master; +} +RefPtr IDEChannel::slave_device() +{ + return m_slave; +} + +IDEChannel::IDEChannel(const IDEController& controller, IOAddressGroup io_group, ChannelType type, bool force_pio) + : IRQHandler(type == ChannelType::Primary ? PATA_PRIMARY_IRQ : PATA_SECONDARY_IRQ) , m_channel_number((type == ChannelType::Primary ? 0 : 1)) - , m_io_base((type == ChannelType::Primary ? 0x1F0 : 0x170)) - , m_control_base((type == ChannelType::Primary ? 0x3f6 : 0x376)) - , m_bus_master_base(PCI::get_BAR4(pci_address()) & 0xfffc) + , m_io_group(io_group) + , m_parent_controller(controller) { disable_irq(); @@ -137,15 +139,15 @@ PATAChannel::PATAChannel(PCI::Address address, ChannelType type, bool force_pio) enable_irq(); } -PATAChannel::~PATAChannel() +IDEChannel::~IDEChannel() { } -void PATAChannel::start_request(AsyncBlockDeviceRequest& request, bool use_dma, bool is_slave) +void IDEChannel::start_request(AsyncBlockDeviceRequest& request, bool use_dma, bool is_slave) { ScopedSpinLock lock(m_request_lock); #ifdef PATA_DEBUG - dbg() << "PATAChannel::start_request"; + dbg() << "IDEChannel::start_request"; #endif m_current_request = &request; m_current_request_block_index = 0; @@ -165,7 +167,7 @@ void PATAChannel::start_request(AsyncBlockDeviceRequest& request, bool use_dma, } } -void PATAChannel::complete_current_request(AsyncDeviceRequest::RequestResult result) +void IDEChannel::complete_current_request(AsyncDeviceRequest::RequestResult result) { // NOTE: this may be called from the interrupt handler! ASSERT(m_current_request); @@ -177,7 +179,7 @@ void PATAChannel::complete_current_request(AsyncDeviceRequest::RequestResult res // before Processor::deferred_call_queue returns! Processor::deferred_call_queue([this, result]() { #ifdef PATA_DEBUG - dbg() << "PATAChannel::complete_current_request result: " << result; + dbg() << "IDEChannel::complete_current_request result: " << result; #endif ASSERT(m_current_request); auto& request = *m_current_request; @@ -193,7 +195,7 @@ void PATAChannel::complete_current_request(AsyncDeviceRequest::RequestResult res } // I read somewhere that this may trigger a cache flush so let's do it. - m_bus_master_base.offset(2).out(m_bus_master_base.offset(2).in() | 0x6); + m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); } } @@ -201,50 +203,50 @@ void PATAChannel::complete_current_request(AsyncDeviceRequest::RequestResult res }); } -void PATAChannel::initialize(bool force_pio) +void IDEChannel::initialize(bool force_pio) { - PCI::enable_interrupt_line(pci_address()); + m_parent_controller->enable_pin_based_interrupts(); if (force_pio) { - klog() << "PATAChannel: Requested to force PIO mode; not setting up DMA"; + klog() << "IDEChannel: Requested to force PIO mode; not setting up DMA"; return; } // Let's try to set up DMA transfers. - PCI::enable_bus_mastering(pci_address()); + 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(); - klog() << "PATAChannel: Bus master IDE: " << m_bus_master_base; + klog() << "IDEChannel: Bus master IDE: " << m_io_group.bus_master_base(); } static void print_ide_status(u8 status) { - klog() << "PATAChannel: print_ide_status: DRQ=" << ((status & ATA_SR_DRQ) != 0) << " BSY=" << ((status & ATA_SR_BSY) != 0) << " DRDY=" << ((status & ATA_SR_DRDY) != 0) << " DSC=" << ((status & ATA_SR_DSC) != 0) << " DF=" << ((status & ATA_SR_DF) != 0) << " CORR=" << ((status & ATA_SR_CORR) != 0) << " IDX=" << ((status & ATA_SR_IDX) != 0) << " ERR=" << ((status & ATA_SR_ERR) != 0); + klog() << "IDEChannel: print_ide_status: DRQ=" << ((status & ATA_SR_DRQ) != 0) << " BSY=" << ((status & ATA_SR_BSY) != 0) << " DRDY=" << ((status & ATA_SR_DRDY) != 0) << " DSC=" << ((status & ATA_SR_DSC) != 0) << " DF=" << ((status & ATA_SR_DF) != 0) << " CORR=" << ((status & ATA_SR_CORR) != 0) << " IDX=" << ((status & ATA_SR_IDX) != 0) << " ERR=" << ((status & ATA_SR_ERR) != 0); } -void PATAChannel::handle_irq(const RegisterState&) +void IDEChannel::handle_irq(const RegisterState&) { - u8 status = m_io_base.offset(ATA_REG_STATUS).in(); + u8 status = m_io_group.io_base().offset(ATA_REG_STATUS).in(); m_entropy_source.add_random_event(status); - u8 bstatus = m_bus_master_base.offset(2).in(); + u8 bstatus = m_io_group.bus_master_base().offset(2).in(); if (!(bstatus & 0x4)) { // interrupt not from this device, ignore #ifdef PATA_DEBUG - klog() << "PATAChannel: ignore interrupt"; + klog() << "IDEChannel: ignore interrupt"; #endif return; } ScopedSpinLock lock(m_request_lock); #ifdef PATA_DEBUG - klog() << "PATAChannel: interrupt: DRQ=" << ((status & ATA_SR_DRQ) != 0) << " BSY=" << ((status & ATA_SR_BSY) != 0) << " DRDY=" << ((status & ATA_SR_DRDY) != 0); + klog() << "IDEChannel: interrupt: DRQ=" << ((status & ATA_SR_DRQ) != 0) << " BSY=" << ((status & ATA_SR_BSY) != 0) << " DRDY=" << ((status & ATA_SR_DRDY) != 0); #endif if (!m_current_request) { #ifdef PATA_DEBUG - dbg() << "PATAChannel: IRQ but no pending request!"; + dbg() << "IDEChannel: IRQ but no pending request!"; #endif return; } @@ -253,8 +255,8 @@ void PATAChannel::handle_irq(const RegisterState&) if (status & ATA_SR_ERR) { print_ide_status(status); - m_device_error = m_io_base.offset(ATA_REG_ERROR).in(); - klog() << "PATAChannel: Error " << String::format("%b", m_device_error) << "!"; + m_device_error = m_io_group.io_base().offset(ATA_REG_ERROR).in(); + klog() << "IDEChannel: Error " << String::format("%b", m_device_error) << "!"; complete_current_request(AsyncDeviceRequest::Failure); return; } @@ -270,7 +272,7 @@ void PATAChannel::handle_irq(const RegisterState&) // trigger page faults Processor::deferred_call_queue([this]() { if (m_current_request->request_type() == AsyncBlockDeviceRequest::Read) { - dbg() << "PATAChannel: Read block " << m_current_request_block_index << "/" << m_current_request->block_count(); + dbg() << "IDEChannel: Read block " << m_current_request_block_index << "/" << m_current_request->block_count(); if (ata_do_read_sector()) { if (++m_current_request_block_index >= m_current_request->block_count()) { complete_current_request(AsyncDeviceRequest::Success); @@ -281,12 +283,12 @@ void PATAChannel::handle_irq(const RegisterState&) } } else { if (!m_current_request_flushing_cache) { - dbg() << "PATAChannel: Wrote block " << m_current_request_block_index << "/" << m_current_request->block_count(); + dbg() << "IDEChannel: Wrote block " << m_current_request_block_index << "/" << m_current_request->block_count(); if (++m_current_request_block_index >= m_current_request->block_count()) { // We read the last block, flush cache ASSERT(!m_current_request_flushing_cache); m_current_request_flushing_cache = true; - m_io_base.offset(ATA_REG_COMMAND).out(ATA_CMD_CACHE_FLUSH); + m_io_group.io_base().offset(ATA_REG_COMMAND).out(ATA_CMD_CACHE_FLUSH); } else { // Read next block ata_do_write_sector(); @@ -305,27 +307,27 @@ static void io_delay() IO::in8(0x3f6); } -void PATAChannel::detect_disks() +void IDEChannel::detect_disks() { // There are only two possible disks connected to a channel for (auto i = 0; i < 2; i++) { - m_io_base.offset(ATA_REG_HDDEVSEL).out(0xA0 | (i << 4)); // First, we need to select the drive itself + m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(0xA0 | (i << 4)); // First, we need to select the drive itself // Apparently these need to be 0 before sending IDENTIFY?! - m_io_base.offset(ATA_REG_SECCOUNT0).out(0x00); - m_io_base.offset(ATA_REG_LBA0).out(0x00); - m_io_base.offset(ATA_REG_LBA1).out(0x00); - m_io_base.offset(ATA_REG_LBA2).out(0x00); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(0x00); + m_io_group.io_base().offset(ATA_REG_LBA0).out(0x00); + m_io_group.io_base().offset(ATA_REG_LBA1).out(0x00); + m_io_group.io_base().offset(ATA_REG_LBA2).out(0x00); - m_io_base.offset(ATA_REG_COMMAND).out(ATA_CMD_IDENTIFY); // Send the ATA_IDENTIFY command + m_io_group.io_base().offset(ATA_REG_COMMAND).out(ATA_CMD_IDENTIFY); // Send the ATA_IDENTIFY command // Wait for the BSY flag to be reset - while (m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_BSY) + while (m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_BSY) ; - if (m_io_base.offset(ATA_REG_STATUS).in() == 0x00) { + if (m_io_group.io_base().offset(ATA_REG_STATUS).in() == 0x00) { #ifdef PATA_DEBUG - klog() << "PATAChannel: No " << (i == 0 ? "master" : "slave") << " disk detected!"; + klog() << "IDEChannel: No " << (i == 0 ? "master" : "slave") << " disk detected!"; #endif continue; } @@ -337,7 +339,7 @@ void PATAChannel::detect_disks() const u16* wbufbase = (u16*)wbuf.data(); for (u32 i = 0; i < 256; ++i) { - u16 data = m_io_base.offset(ATA_REG_DATA).in(); + u16 data = m_io_group.io_base().offset(ATA_REG_DATA).in(); *(w++) = data; *(b++) = MSB(data); *(b++) = LSB(data); @@ -350,26 +352,25 @@ void PATAChannel::detect_disks() u8 cyls = wbufbase[1]; u8 heads = wbufbase[3]; u8 spt = wbufbase[6]; - - klog() << "PATAChannel: Name=" << ((char*)bbuf.data() + 54) << ", C/H/Spt=" << cyls << "/" << heads << "/" << spt; + if (cyls == 0 || heads == 0 || spt == 0) + continue; + klog() << "IDEChannel: Name=" << ((char*)bbuf.data() + 54) << ", C/H/Spt=" << cyls << "/" << heads << "/" << spt; int major = (m_channel_number == 0) ? 3 : 4; if (i == 0) { - m_master = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Master, major, 0); - m_master->set_drive_geometry(cyls, heads, spt); + m_master = PATADiskDevice::create(m_parent_controller, *this, PATADiskDevice::DriveType::Master, cyls, heads, spt, major, 0); } else { - m_slave = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Slave, major, 1); - m_slave->set_drive_geometry(cyls, heads, spt); + m_slave = PATADiskDevice::create(m_parent_controller, *this, PATADiskDevice::DriveType::Slave, cyls, heads, spt, major, 1); } } } -void PATAChannel::ata_read_sectors_with_dma(bool slave_request) +void IDEChannel::ata_read_sectors_with_dma(bool slave_request) { auto& request = *m_current_request; u32 lba = request.block_index(); #ifdef PATA_DEBUG - dbg() << "PATAChannel::ata_read_sectors_with_dma (" << lba << " x" << request.block_count() << ")"; + dbg() << "IDEChannel::ata_read_sectors_with_dma (" << lba << " x" << request.block_count() << ")"; #endif prdt().offset = m_dma_buffer_page->paddr(); @@ -378,57 +379,57 @@ void PATAChannel::ata_read_sectors_with_dma(bool slave_request) ASSERT(prdt().size <= PAGE_SIZE); // Stop bus master - m_bus_master_base.out(0); + m_io_group.bus_master_base().out(0); // Write the PRDT location - m_bus_master_base.offset(4).out(m_prdt_page->paddr().get()); + 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_bus_master_base.offset(2).out(m_bus_master_base.offset(2).in() | 0x6); + m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); // Set transfer direction - m_bus_master_base.out(0x8); + m_io_group.bus_master_base().out(0x8); - while (m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_BSY) + while (m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_BSY) ; - m_control_base.offset(ATA_CTL_CONTROL).out(0); - m_io_base.offset(ATA_REG_HDDEVSEL).out(0x40 | (static_cast(slave_request) << 4)); + m_io_group.control_base().offset(ATA_CTL_CONTROL).out(0); + m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(0x40 | (static_cast(slave_request) << 4)); io_delay(); - m_io_base.offset(ATA_REG_FEATURES).out(0); + m_io_group.io_base().offset(ATA_REG_FEATURES).out(0); - m_io_base.offset(ATA_REG_SECCOUNT0).out(0); - m_io_base.offset(ATA_REG_LBA0).out(0); - m_io_base.offset(ATA_REG_LBA1).out(0); - m_io_base.offset(ATA_REG_LBA2).out(0); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(0); + m_io_group.io_base().offset(ATA_REG_LBA0).out(0); + m_io_group.io_base().offset(ATA_REG_LBA1).out(0); + m_io_group.io_base().offset(ATA_REG_LBA2).out(0); - m_io_base.offset(ATA_REG_SECCOUNT0).out(request.block_count()); - m_io_base.offset(ATA_REG_LBA0).out((lba & 0x000000ff) >> 0); - m_io_base.offset(ATA_REG_LBA1).out((lba & 0x0000ff00) >> 8); - m_io_base.offset(ATA_REG_LBA2).out((lba & 0x00ff0000) >> 16); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(request.block_count()); + m_io_group.io_base().offset(ATA_REG_LBA0).out((lba & 0x000000ff) >> 0); + m_io_group.io_base().offset(ATA_REG_LBA1).out((lba & 0x0000ff00) >> 8); + m_io_group.io_base().offset(ATA_REG_LBA2).out((lba & 0x00ff0000) >> 16); for (;;) { - auto status = m_io_base.offset(ATA_REG_STATUS).in(); + auto status = m_io_group.io_base().offset(ATA_REG_STATUS).in(); if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; } - m_io_base.offset(ATA_REG_COMMAND).out(ATA_CMD_READ_DMA_EXT); + m_io_group.io_base().offset(ATA_REG_COMMAND).out(ATA_CMD_READ_DMA_EXT); io_delay(); enable_irq(); // Start bus master - m_bus_master_base.out(0x9); + m_io_group.bus_master_base().out(0x9); } -bool PATAChannel::ata_do_read_sector() +bool IDEChannel::ata_do_read_sector() { auto& request = *m_current_request; auto out_buffer = request.buffer().offset(m_current_request_block_index * 512); ssize_t nwritten = request.write_to_buffer_buffered<512>(out_buffer, 512, [&](u8* buffer, size_t buffer_bytes) { for (size_t i = 0; i < buffer_bytes; i += sizeof(u16)) - *(u16*)&buffer[i] = IO::in16(m_io_base.offset(ATA_REG_DATA).get()); + *(u16*)&buffer[i] = IO::in16(m_io_group.io_base().offset(ATA_REG_DATA).get()); return (ssize_t)buffer_bytes; }); if (nwritten < 0) { @@ -439,58 +440,58 @@ bool PATAChannel::ata_do_read_sector() return true; } -void PATAChannel::ata_read_sectors(bool slave_request) +void IDEChannel::ata_read_sectors(bool slave_request) { auto& request = *m_current_request; ASSERT(request.block_count() <= 256); #ifdef PATA_DEBUG - dbg() << "PATAChannel::ata_read_sectors"; + dbg() << "IDEChannel::ata_read_sectors"; #endif - while (m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_BSY) + while (m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_BSY) ; auto lba = request.block_index(); #ifdef PATA_DEBUG - klog() << "PATAChannel: Reading " << request.block_count() << " sector(s) @ LBA " << lba; + klog() << "IDEChannel: Reading " << request.block_count() << " sector(s) @ LBA " << lba; #endif u8 devsel = 0xe0; if (slave_request) devsel |= 0x10; - m_control_base.offset(ATA_CTL_CONTROL).out(0); - m_io_base.offset(ATA_REG_HDDEVSEL).out(devsel | (static_cast(slave_request) << 4) | 0x40); + m_io_group.control_base().offset(ATA_CTL_CONTROL).out(0); + m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(devsel | (static_cast(slave_request) << 4) | 0x40); io_delay(); - m_io_base.offset(ATA_REG_FEATURES).out(0); + m_io_group.io_base().offset(ATA_REG_FEATURES).out(0); - m_io_base.offset(ATA_REG_SECCOUNT0).out(0); - m_io_base.offset(ATA_REG_LBA0).out(0); - m_io_base.offset(ATA_REG_LBA1).out(0); - m_io_base.offset(ATA_REG_LBA2).out(0); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(0); + m_io_group.io_base().offset(ATA_REG_LBA0).out(0); + m_io_group.io_base().offset(ATA_REG_LBA1).out(0); + m_io_group.io_base().offset(ATA_REG_LBA2).out(0); - m_io_base.offset(ATA_REG_SECCOUNT0).out(request.block_count()); - m_io_base.offset(ATA_REG_LBA0).out((lba & 0x000000ff) >> 0); - m_io_base.offset(ATA_REG_LBA1).out((lba & 0x0000ff00) >> 8); - m_io_base.offset(ATA_REG_LBA2).out((lba & 0x00ff0000) >> 16); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(request.block_count()); + m_io_group.io_base().offset(ATA_REG_LBA0).out((lba & 0x000000ff) >> 0); + m_io_group.io_base().offset(ATA_REG_LBA1).out((lba & 0x0000ff00) >> 8); + m_io_group.io_base().offset(ATA_REG_LBA2).out((lba & 0x00ff0000) >> 16); for (;;) { - auto status = m_io_base.offset(ATA_REG_STATUS).in(); + auto status = m_io_group.io_base().offset(ATA_REG_STATUS).in(); if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; } enable_irq(); - m_io_base.offset(ATA_REG_COMMAND).out(ATA_CMD_READ_PIO); + m_io_group.io_base().offset(ATA_REG_COMMAND).out(ATA_CMD_READ_PIO); } -void PATAChannel::ata_write_sectors_with_dma(bool slave_request) +void IDEChannel::ata_write_sectors_with_dma(bool slave_request) { auto& request = *m_current_request; u32 lba = request.block_index(); #ifdef PATA_DEBUG - dbg() << "PATAChannel::ata_write_sectors_with_dma (" << lba << " x" << request.block_count() << ")"; + dbg() << "IDEChannel::ata_write_sectors_with_dma (" << lba << " x" << request.block_count() << ")"; #endif prdt().offset = m_dma_buffer_page->paddr(); @@ -504,72 +505,72 @@ void PATAChannel::ata_write_sectors_with_dma(bool slave_request) ASSERT(prdt().size <= PAGE_SIZE); // Stop bus master - m_bus_master_base.out(0); + m_io_group.bus_master_base().out(0); // Write the PRDT location - m_bus_master_base.offset(4).out(m_prdt_page->paddr().get()); + 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_bus_master_base.offset(2).out(m_bus_master_base.offset(2).in() | 0x6); + m_io_group.bus_master_base().offset(2).out(m_io_group.bus_master_base().offset(2).in() | 0x6); - while (m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_BSY) + while (m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_BSY) ; - m_control_base.offset(ATA_CTL_CONTROL).out(0); - m_io_base.offset(ATA_REG_HDDEVSEL).out(0x40 | (static_cast(slave_request) << 4)); + m_io_group.control_base().offset(ATA_CTL_CONTROL).out(0); + m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(0x40 | (static_cast(slave_request) << 4)); io_delay(); - m_io_base.offset(ATA_REG_FEATURES).out(0); + m_io_group.io_base().offset(ATA_REG_FEATURES).out(0); - m_io_base.offset(ATA_REG_SECCOUNT0).out(0); - m_io_base.offset(ATA_REG_LBA0).out(0); - m_io_base.offset(ATA_REG_LBA1).out(0); - m_io_base.offset(ATA_REG_LBA2).out(0); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(0); + m_io_group.io_base().offset(ATA_REG_LBA0).out(0); + m_io_group.io_base().offset(ATA_REG_LBA1).out(0); + m_io_group.io_base().offset(ATA_REG_LBA2).out(0); - m_io_base.offset(ATA_REG_SECCOUNT0).out(request.block_count()); - m_io_base.offset(ATA_REG_LBA0).out((lba & 0x000000ff) >> 0); - m_io_base.offset(ATA_REG_LBA1).out((lba & 0x0000ff00) >> 8); - m_io_base.offset(ATA_REG_LBA2).out((lba & 0x00ff0000) >> 16); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(request.block_count()); + m_io_group.io_base().offset(ATA_REG_LBA0).out((lba & 0x000000ff) >> 0); + m_io_group.io_base().offset(ATA_REG_LBA1).out((lba & 0x0000ff00) >> 8); + m_io_group.io_base().offset(ATA_REG_LBA2).out((lba & 0x00ff0000) >> 16); for (;;) { - auto status = m_io_base.offset(ATA_REG_STATUS).in(); + auto status = m_io_group.io_base().offset(ATA_REG_STATUS).in(); if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; } - m_io_base.offset(ATA_REG_COMMAND).out(ATA_CMD_WRITE_DMA_EXT); + m_io_group.io_base().offset(ATA_REG_COMMAND).out(ATA_CMD_WRITE_DMA_EXT); io_delay(); enable_irq(); // Start bus master - m_bus_master_base.out(0x1); + m_io_group.bus_master_base().out(0x1); } -void PATAChannel::ata_do_write_sector() +void IDEChannel::ata_do_write_sector() { auto& request = *m_current_request; io_delay(); - while ((m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_BSY) || !(m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_DRQ)) + while ((m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_BSY) || !(m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_DRQ)) ; - u8 status = m_io_base.offset(ATA_REG_STATUS).in(); + u8 status = m_io_group.io_base().offset(ATA_REG_STATUS).in(); ASSERT(status & ATA_SR_DRQ); auto in_buffer = request.buffer().offset(m_current_request_block_index * 512); #ifdef PATA_DEBUG - dbg() << "PATAChannel: Writing 512 bytes (part " << m_current_request_block_index << ") (status=" << String::format("%b", status) << ")..."; + dbg() << "IDEChannel: Writing 512 bytes (part " << m_current_request_block_index << ") (status=" << String::format("%b", status) << ")..."; #endif ssize_t nread = request.read_from_buffer_buffered<512>(in_buffer, 512, [&](const u8* buffer, size_t buffer_bytes) { for (size_t i = 0; i < buffer_bytes; i += sizeof(u16)) - IO::out16(m_io_base.offset(ATA_REG_DATA).get(), *(const u16*)&buffer[i]); + IO::out16(m_io_group.io_base().offset(ATA_REG_DATA).get(), *(const u16*)&buffer[i]); return (ssize_t)buffer_bytes; }); if (nread < 0) complete_current_request(AsyncDeviceRequest::MemoryFault); } -void PATAChannel::ata_write_sectors(bool slave_request) +void IDEChannel::ata_write_sectors(bool slave_request) { auto& request = *m_current_request; @@ -577,34 +578,34 @@ void PATAChannel::ata_write_sectors(bool slave_request) u32 start_sector = request.block_index(); u32 count = request.block_count(); #ifdef PATA_DEBUG - klog() << "PATAChannel::ata_write_sectors request (" << count << " sector(s) @ " << start_sector << ")"; + klog() << "IDEChannel::ata_write_sectors request (" << count << " sector(s) @ " << start_sector << ")"; #endif - while (m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_BSY) + while (m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_BSY) ; #ifdef PATA_DEBUG - klog() << "PATAChannel: Writing " << count << " sector(s) @ LBA " << start_sector; + klog() << "IDEChannel: Writing " << count << " sector(s) @ LBA " << start_sector; #endif u8 devsel = 0xe0; if (slave_request) devsel |= 0x10; - m_io_base.offset(ATA_REG_SECCOUNT0).out(count == 256 ? 0 : LSB(count)); - m_io_base.offset(ATA_REG_LBA0).out(start_sector & 0xff); - m_io_base.offset(ATA_REG_LBA1).out((start_sector >> 8) & 0xff); - m_io_base.offset(ATA_REG_LBA2).out((start_sector >> 16) & 0xff); - m_io_base.offset(ATA_REG_HDDEVSEL).out(devsel | ((start_sector >> 24) & 0xf)); + m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out(count == 256 ? 0 : LSB(count)); + m_io_group.io_base().offset(ATA_REG_LBA0).out(start_sector & 0xff); + m_io_group.io_base().offset(ATA_REG_LBA1).out((start_sector >> 8) & 0xff); + m_io_group.io_base().offset(ATA_REG_LBA2).out((start_sector >> 16) & 0xff); + m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out(devsel | ((start_sector >> 24) & 0xf)); IO::out8(0x3F6, 0x08); - while (!(m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_DRDY)) + while (!(m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_DRDY)) ; - m_io_base.offset(ATA_REG_COMMAND).out(ATA_CMD_WRITE_PIO); + m_io_group.io_base().offset(ATA_REG_COMMAND).out(ATA_CMD_WRITE_PIO); io_delay(); - while ((m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_BSY) || !(m_io_base.offset(ATA_REG_STATUS).in() & ATA_SR_DRQ)) + while ((m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_BSY) || !(m_io_group.io_base().offset(ATA_REG_STATUS).in() & ATA_SR_DRQ)) ; enable_irq(); diff --git a/Kernel/Devices/PATAChannel.h b/Kernel/Storage/IDEChannel.h similarity index 65% rename from Kernel/Devices/PATAChannel.h rename to Kernel/Storage/IDEChannel.h index e696abfe44d..ae2cfea5f32 100644 --- a/Kernel/Devices/PATAChannel.h +++ b/Kernel/Storage/IDEChannel.h @@ -41,11 +41,11 @@ #include #include #include +#include #include -#include -#include #include #include +#include #include #include @@ -59,8 +59,9 @@ struct PhysicalRegionDescriptor { u16 end_of_table { 0 }; }; -class PATADiskDevice; -class PATAChannel final : public PCI::Device { +class IDEController; +class IDEChannel final : public IRQHandler { + friend class IDEController; friend class PATADiskDevice; AK_MAKE_ETERNAL public: @@ -69,13 +70,46 @@ public: Secondary }; -public: - static OwnPtr create(ChannelType type, bool force_pio); - PATAChannel(PCI::Address address, ChannelType type, bool force_pio); - virtual ~PATAChannel() override; + struct IOAddressGroup { + IOAddressGroup(IOAddress io_base, IOAddress control_base, IOAddress bus_master_base) + : m_io_base(io_base) + , m_control_base(control_base) + , m_bus_master_base(bus_master_base) + { + } - RefPtr master_device() { return m_master; }; - RefPtr slave_device() { return m_slave; }; + // Disable default implementations that would use surprising integer promotion. + bool operator==(const IOAddressGroup&) const = delete; + bool operator<=(const IOAddressGroup&) const = delete; + bool operator>=(const IOAddressGroup&) const = delete; + bool operator<(const IOAddressGroup&) const = delete; + bool operator>(const IOAddressGroup&) const = delete; + + IOAddress io_base() const { return m_io_base; }; + IOAddress control_base() const { return m_control_base; } + IOAddress bus_master_base() const { return m_bus_master_base; } + + const IOAddressGroup& operator=(const IOAddressGroup& group) + { + m_io_base = group.io_base(); + m_control_base = group.control_base(); + m_bus_master_base = group.bus_master_base(); + return *this; + } + + private: + IOAddress m_io_base; + IOAddress m_control_base; + IOAddress m_bus_master_base; + }; + +public: + static NonnullOwnPtr create(const IDEController&, IOAddressGroup, ChannelType type, bool force_pio); + IDEChannel(const IDEController&, IOAddressGroup, ChannelType type, bool force_pio); + virtual ~IDEChannel() override; + + RefPtr master_device(); + RefPtr slave_device(); virtual const char* purpose() const override { return "PATA Channel"; } @@ -98,24 +132,25 @@ private: // Data members u8 m_channel_number { 0 }; // Channel number. 0 = master, 1 = slave - IOAddress m_io_base; - IOAddress m_control_base; + 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; - IOAddress m_bus_master_base; Lockable m_dma_enabled; EntropySource m_entropy_source; - RefPtr m_master; - RefPtr m_slave; + RefPtr m_master; + RefPtr m_slave; 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; + + IOAddressGroup m_io_group; + NonnullRefPtr m_parent_controller; }; } diff --git a/Kernel/Storage/IDEController.cpp b/Kernel/Storage/IDEController.cpp new file mode 100644 index 00000000000..00e89284ce4 --- /dev/null +++ b/Kernel/Storage/IDEController.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020, 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 +#include + +namespace Kernel { + +NonnullRefPtr IDEController::initialize(PCI::Address address, bool force_pio) +{ + return adopt(*new IDEController(address, force_pio)); +} + +bool IDEController::reset() +{ + TODO(); +} + +bool IDEController::shutdown() +{ + TODO(); +} + +void IDEController::start_request(const StorageDevice&, AsyncBlockDeviceRequest&) +{ + ASSERT_NOT_REACHED(); +} + +void IDEController::complete_current_request(AsyncDeviceRequest::RequestResult) +{ + ASSERT_NOT_REACHED(); +} + +IDEController::IDEController(PCI::Address address, bool force_pio) + : StorageController(address) +{ + initialize(force_pio); +} + +IDEController::~IDEController() +{ +} + +void IDEController::initialize(bool force_pio) +{ + auto bus_master_base = IOAddress(PCI::get_BAR4(pci_address()) & (~1)); + + auto bar0 = PCI::get_BAR0(pci_address()); + auto base_io = (bar0 == 0x1 || bar0 == 0) ? IOAddress(0x1F0) : IOAddress(bar0); + 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)); + + 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)); +} + +RefPtr IDEController::device(u32 index) +{ + switch (index) { + case 0: + return m_channels[0].master_device(); + case 1: + return m_channels[0].slave_device(); + case 2: + return m_channels[1].master_device(); + case 3: + return m_channels[1].slave_device(); + } + return nullptr; +} + +} diff --git a/Kernel/Storage/IDEController.h b/Kernel/Storage/IDEController.h new file mode 100644 index 00000000000..757c8c59563 --- /dev/null +++ b/Kernel/Storage/IDEController.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020, 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 +#include +#include +#include +#include + +namespace Kernel { + +class AsyncBlockDeviceRequest; + +class IDEController final : public StorageController { + AK_MAKE_ETERNAL +public: +public: + static NonnullRefPtr initialize(PCI::Address address, bool force_pio); + virtual ~IDEController() override; + + virtual RefPtr device(u32 index) override; + virtual bool reset() override; + virtual bool shutdown() override; + virtual void start_request(const StorageDevice&, AsyncBlockDeviceRequest&) override; + virtual void complete_current_request(AsyncDeviceRequest::RequestResult) override; + +private: + IDEController(PCI::Address address, bool force_pio); + + void initialize(bool force_pio); + void detect_disks(); + + NonnullOwnPtrVector m_channels; +}; +} diff --git a/Kernel/Storage/PATADiskDevice.cpp b/Kernel/Storage/PATADiskDevice.cpp new file mode 100644 index 00000000000..21ee558eef1 --- /dev/null +++ b/Kernel/Storage/PATADiskDevice.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * 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. + */ + +//#define PATA_DEVICE_DEBUG + +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +NonnullRefPtr PATADiskDevice::create(const IDEController& controller, IDEChannel& channel, DriveType type, u8 cylinders, u8 heads, u8 spt, int major, int minor) +{ + return adopt(*new PATADiskDevice(controller, channel, type, cylinders, heads, spt, major, minor)); +} + +PATADiskDevice::PATADiskDevice(const IDEController& controller, IDEChannel& channel, DriveType type, u8 cylinders, u8 heads, u8 spt, int major, int minor) + : StorageDevice(controller, major, minor, 512, 0) + , m_cylinders(cylinders) + , m_heads(heads) + , m_sectors_per_track(spt) + , m_channel(channel) + , m_drive_type(type) +{ +} + +PATADiskDevice::~PATADiskDevice() +{ +} + +const char* PATADiskDevice::class_name() const +{ + return "PATADiskDevice"; +} + +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()); +} + +size_t PATADiskDevice::max_addressable_block() const +{ + return m_cylinders * m_heads * m_sectors_per_track; +} + +bool PATADiskDevice::is_slave() const +{ + return m_drive_type == DriveType::Slave; +} + +} diff --git a/Kernel/Devices/PATADiskDevice.h b/Kernel/Storage/PATADiskDevice.h similarity index 76% rename from Kernel/Devices/PATADiskDevice.h rename to Kernel/Storage/PATADiskDevice.h index 1036b06fd5e..fa19186c6ac 100644 --- a/Kernel/Devices/PATADiskDevice.h +++ b/Kernel/Storage/PATADiskDevice.h @@ -30,15 +30,16 @@ #pragma once -#include #include #include +#include namespace Kernel { -class PATAChannel; +class IDEController; -class PATADiskDevice final : public BlockDevice { +class PATADiskDevice final : public StorageDevice { + friend class IDEController; AK_MAKE_ETERNAL public: // Type of drive this IDEDiskDevice is on the ATA channel. @@ -51,22 +52,19 @@ public: }; public: - static NonnullRefPtr create(PATAChannel&, DriveType, int major, int minor); + static NonnullRefPtr create(const IDEController&, IDEChannel&, DriveType, u8, u8, u8, int major, int minor); virtual ~PATADiskDevice() override; - void set_drive_geometry(u16, u16, u16); + // ^StorageDevice + virtual Type type() const override { return StorageDevice::Type::IDE; } + virtual size_t max_addressable_block() const override; // ^BlockDevice virtual void start_request(AsyncBlockDeviceRequest&) override; - virtual KResultOr read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; - virtual bool can_read(const FileDescription&, size_t) const override; - virtual KResultOr write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override; - virtual bool can_write(const FileDescription&, size_t) const override; - -protected: - explicit PATADiskDevice(PATAChannel&, DriveType, int, int); private: + PATADiskDevice(const IDEController&, IDEChannel&, DriveType, u8, u8, u8, int major, int minor); + // ^DiskDevice virtual const char* class_name() const override; @@ -76,9 +74,8 @@ private: u16 m_cylinders { 0 }; u16 m_heads { 0 }; u16 m_sectors_per_track { 0 }; + IDEChannel& m_channel; DriveType m_drive_type { DriveType::Master }; - - PATAChannel& m_channel; }; } diff --git a/Kernel/Storage/StorageController.h b/Kernel/Storage/StorageController.h new file mode 100644 index 00000000000..9f01156b26b --- /dev/null +++ b/Kernel/Storage/StorageController.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class AsyncBlockDeviceRequest; +class StorageDevice; +class StorageController : public RefCounted + , public PCI::DeviceController { + AK_MAKE_ETERNAL +public: +protected: + explicit StorageController(PCI::Address address) + : PCI::DeviceController(address) + { + } + + virtual RefPtr device(u32 index) = 0; + virtual void start_request(const StorageDevice&, AsyncBlockDeviceRequest&) = 0; + +protected: + virtual bool reset() = 0; + virtual bool shutdown() = 0; + + virtual void complete_current_request(AsyncDeviceRequest::RequestResult) = 0; +}; +} diff --git a/Kernel/Devices/PATADiskDevice.cpp b/Kernel/Storage/StorageDevice.cpp similarity index 78% rename from Kernel/Devices/PATADiskDevice.cpp rename to Kernel/Storage/StorageDevice.cpp index 8b85783a5ba..9dcb17ea38a 100644 --- a/Kernel/Devices/PATADiskDevice.cpp +++ b/Kernel/Storage/StorageDevice.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2020, Liav A. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,51 +24,33 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -//#define PATA_DEVICE_DEBUG +//#define STORAGE_DEVICE_DEBUG #include #include -#include -#include #include +#include namespace Kernel { -NonnullRefPtr PATADiskDevice::create(PATAChannel& channel, DriveType type, int major, int minor) -{ - return adopt(*new PATADiskDevice(channel, type, major, minor)); -} - -PATADiskDevice::PATADiskDevice(PATAChannel& channel, DriveType type, int major, int minor) - : BlockDevice(major, minor, 512) - , m_drive_type(type) - , m_channel(channel) +StorageDevice::StorageDevice(const StorageController& controller, int major, int minor, size_t sector_size, size_t max_addressable_block) + : BlockDevice(major, minor, sector_size) + , m_storage_controller(controller) + , m_max_addressable_block(max_addressable_block) { } -PATADiskDevice::~PATADiskDevice() +const char* StorageDevice::class_name() const { + return "StorageDevice"; } -const char* PATADiskDevice::class_name() const +NonnullRefPtr StorageDevice::controller() const { - return "PATADiskDevice"; + return m_storage_controller; } -void PATADiskDevice::start_request(AsyncBlockDeviceRequest& request) -{ - bool use_dma = !m_channel.m_bus_master_base.is_null() && m_channel.m_dma_enabled.resource(); - m_channel.start_request(request, use_dma, is_slave()); -} - -void PATADiskDevice::set_drive_geometry(u16 cyls, u16 heads, u16 spt) -{ - m_cylinders = cyls; - m_heads = heads; - m_sectors_per_track = spt; -} - -KResultOr PATADiskDevice::read(FileDescription&, size_t offset, UserOrKernelBuffer& outbuf, size_t len) +KResultOr StorageDevice::read(FileDescription&, size_t offset, UserOrKernelBuffer& outbuf, size_t len) { unsigned index = offset / block_size(); u16 whole_blocks = len / block_size(); @@ -83,8 +65,8 @@ KResultOr PATADiskDevice::read(FileDescription&, size_t offset, UserOrKe remaining = 0; } -#ifdef PATA_DEVICE_DEBUG - klog() << "PATADiskDevice::read() index=" << index << " whole_blocks=" << whole_blocks << " remaining=" << remaining; +#ifdef STORAGE_DEVICE_DEBUG + klog() << "StorageDevice::read() index=" << index << " whole_blocks=" << whole_blocks << " remaining=" << remaining; #endif if (whole_blocks > 0) { @@ -130,12 +112,12 @@ KResultOr PATADiskDevice::read(FileDescription&, size_t offset, UserOrKe return pos + remaining; } -bool PATADiskDevice::can_read(const FileDescription&, size_t offset) const +bool StorageDevice::can_read(const FileDescription&, size_t offset) const { - return offset < (m_cylinders * m_heads * m_sectors_per_track * block_size()); + return offset < (max_addressable_block() * block_size()); } -KResultOr PATADiskDevice::write(FileDescription&, size_t offset, const UserOrKernelBuffer& inbuf, size_t len) +KResultOr StorageDevice::write(FileDescription&, size_t offset, const UserOrKernelBuffer& inbuf, size_t len) { unsigned index = offset / block_size(); u16 whole_blocks = len / block_size(); @@ -150,8 +132,8 @@ KResultOr PATADiskDevice::write(FileDescription&, size_t offset, const U remaining = 0; } -#ifdef PATA_DEVICE_DEBUG - klog() << "PATADiskDevice::write() index=" << index << " whole_blocks=" << whole_blocks << " remaining=" << remaining; +#ifdef STORAGE_DEVICE_DEBUG + klog() << "StorageDevice::write() index=" << index << " whole_blocks=" << whole_blocks << " remaining=" << remaining; #endif if (whole_blocks > 0) { @@ -222,14 +204,9 @@ KResultOr PATADiskDevice::write(FileDescription&, size_t offset, const U return pos + remaining; } -bool PATADiskDevice::can_write(const FileDescription&, size_t offset) const +bool StorageDevice::can_write(const FileDescription&, size_t offset) const { - return offset < (m_cylinders * m_heads * m_sectors_per_track * block_size()); -} - -bool PATADiskDevice::is_slave() const -{ - return m_drive_type == DriveType::Slave; + return offset < (max_addressable_block() * block_size()); } } diff --git a/Kernel/Storage/StorageDevice.h b/Kernel/Storage/StorageDevice.h new file mode 100644 index 00000000000..8cc4f8fed95 --- /dev/null +++ b/Kernel/Storage/StorageDevice.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020, 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 +#include +#include + +namespace Kernel { + +class StorageDevice : public BlockDevice { + AK_MAKE_ETERNAL +public: + enum class Type : u8 { + IDE, + NVMe, + }; + +public: + virtual Type type() const = 0; + virtual size_t max_addressable_block() const { return m_max_addressable_block; } + + NonnullRefPtr controller() const; + + // ^BlockDevice + virtual KResultOr read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; + virtual bool can_read(const FileDescription&, size_t) const override; + virtual KResultOr write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override; + virtual bool can_write(const FileDescription&, size_t) const override; + +protected: + StorageDevice(const StorageController&, int, int, size_t, size_t); + // ^DiskDevice + virtual const char* class_name() const override; + +private: + NonnullRefPtr m_storage_controller; + size_t m_max_addressable_block; +}; + +} diff --git a/Kernel/init.cpp b/Kernel/init.cpp index f4e2e613abf..fa119c8e876 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -40,8 +40,6 @@ #include #include #include -#include -#include #include #include #include @@ -67,6 +65,8 @@ #include #include #include +#include +#include #include #include #include @@ -276,8 +276,15 @@ void init_stage2(void*) Processor::halt(); } - auto pata0 = PATAChannel::create(PATAChannel::ChannelType::Primary, force_pio); - NonnullRefPtr root_dev = *pata0->master_device(); + RefPtr checked_root_dev; + PCI::enumerate([&](const PCI::Address& address, PCI::ID) { + if (PCI::get_class(address) == 0x1 && PCI::get_subclass(address) == 0x1) { + auto pata0 = IDEController::initialize(address, force_pio); + checked_root_dev = *pata0->device(0); + } + }); + ASSERT(!checked_root_dev.is_null()); + NonnullRefPtr root_dev = checked_root_dev.release_nonnull(); root = root.substring(strlen("/dev/hda"), root.length() - strlen("/dev/hda"));