mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 08:32:43 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									39c1783387
								
							
						
					
					
						commit
						0a2b00a1bf
					
				
					 12 changed files with 604 additions and 213 deletions
				
			
		|  | @ -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") | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -27,11 +27,12 @@ | |||
| #include <AK/ByteBuffer.h> | ||||
| #include <AK/Singleton.h> | ||||
| #include <AK/StringView.h> | ||||
| #include <Kernel/Devices/PATAChannel.h> | ||||
| #include <Kernel/Devices/PATADiskDevice.h> | ||||
| #include <Kernel/FileSystem/ProcFS.h> | ||||
| #include <Kernel/IO.h> | ||||
| #include <Kernel/Process.h> | ||||
| #include <Kernel/Storage/IDEChannel.h> | ||||
| #include <Kernel/Storage/IDEController.h> | ||||
| #include <Kernel/Storage/PATADiskDevice.h> | ||||
| #include <Kernel/VM/MemoryManager.h> | ||||
| 
 | ||||
| namespace Kernel { | ||||
|  | @ -108,24 +109,25 @@ namespace Kernel { | |||
| #define PCI_Mass_Storage_Class 0x1 | ||||
| #define PCI_IDE_Controller_Subclass 0x1 | ||||
| 
 | ||||
| OwnPtr<PATAChannel> PATAChannel::create(ChannelType type, bool force_pio) | ||||
| NonnullOwnPtr<IDEChannel> 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<PATAChannel>(pci_address, type, force_pio); | ||||
|     return make<IDEChannel>(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<StorageDevice> IDEChannel::master_device() | ||||
| { | ||||
|     return m_master; | ||||
| } | ||||
| RefPtr<StorageDevice> 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<u8>(m_bus_master_base.offset(2).in<u8>() | 0x6); | ||||
|                 m_io_group.bus_master_base().offset(2).out<u8>(m_io_group.bus_master_base().offset(2).in<u8>() | 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>(); | ||||
|     u8 status = m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>(); | ||||
| 
 | ||||
|     m_entropy_source.add_random_event(status); | ||||
| 
 | ||||
|     u8 bstatus = m_bus_master_base.offset(2).in<u8>(); | ||||
|     u8 bstatus = m_io_group.bus_master_base().offset(2).in<u8>(); | ||||
|     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<u8>(); | ||||
|         klog() << "PATAChannel: Error " << String::format("%b", m_device_error) << "!"; | ||||
|         m_device_error = m_io_group.io_base().offset(ATA_REG_ERROR).in<u8>(); | ||||
|         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<u8>(ATA_CMD_CACHE_FLUSH); | ||||
|                         m_io_group.io_base().offset(ATA_REG_COMMAND).out<u8>(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<u8>(0xA0 | (i << 4)); // First, we need to select the drive itself
 | ||||
|         m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out<u8>(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<u8>(0x00); | ||||
|         m_io_base.offset(ATA_REG_LBA0).out<u8>(0x00); | ||||
|         m_io_base.offset(ATA_REG_LBA1).out<u8>(0x00); | ||||
|         m_io_base.offset(ATA_REG_LBA2).out<u8>(0x00); | ||||
|         m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(0x00); | ||||
|         m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>(0x00); | ||||
|         m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>(0x00); | ||||
|         m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>(0x00); | ||||
| 
 | ||||
|         m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_IDENTIFY); // Send the ATA_IDENTIFY command
 | ||||
|         m_io_group.io_base().offset(ATA_REG_COMMAND).out<u8>(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<u8>() & ATA_SR_BSY) | ||||
|         while (m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) | ||||
|             ; | ||||
| 
 | ||||
|         if (m_io_base.offset(ATA_REG_STATUS).in<u8>() == 0x00) { | ||||
|         if (m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() == 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>(); | ||||
|             u16 data = m_io_group.io_base().offset(ATA_REG_DATA).in<u16>(); | ||||
|             *(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<u8>(0); | ||||
|     m_io_group.bus_master_base().out<u8>(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<u8>(m_bus_master_base.offset(2).in<u8>() | 0x6); | ||||
|     m_io_group.bus_master_base().offset(2).out<u8>(m_io_group.bus_master_base().offset(2).in<u8>() | 0x6); | ||||
| 
 | ||||
|     // Set transfer direction
 | ||||
|     m_bus_master_base.out<u8>(0x8); | ||||
|     m_io_group.bus_master_base().out<u8>(0x8); | ||||
| 
 | ||||
|     while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) | ||||
|     while (m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) | ||||
|         ; | ||||
| 
 | ||||
|     m_control_base.offset(ATA_CTL_CONTROL).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_HDDEVSEL).out<u8>(0x40 | (static_cast<u8>(slave_request) << 4)); | ||||
|     m_io_group.control_base().offset(ATA_CTL_CONTROL).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out<u8>(0x40 | (static_cast<u8>(slave_request) << 4)); | ||||
|     io_delay(); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_FEATURES).out<u16>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_FEATURES).out<u16>(0); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA0).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA1).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA2).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>(0); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(request.block_count()); | ||||
|     m_io_base.offset(ATA_REG_LBA0).out<u8>((lba & 0x000000ff) >> 0); | ||||
|     m_io_base.offset(ATA_REG_LBA1).out<u8>((lba & 0x0000ff00) >> 8); | ||||
|     m_io_base.offset(ATA_REG_LBA2).out<u8>((lba & 0x00ff0000) >> 16); | ||||
|     m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(request.block_count()); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>((lba & 0x000000ff) >> 0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>((lba & 0x0000ff00) >> 8); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>((lba & 0x00ff0000) >> 16); | ||||
| 
 | ||||
|     for (;;) { | ||||
|         auto status = m_io_base.offset(ATA_REG_STATUS).in<u8>(); | ||||
|         auto status = m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>(); | ||||
|         if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_READ_DMA_EXT); | ||||
|     m_io_group.io_base().offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_READ_DMA_EXT); | ||||
|     io_delay(); | ||||
| 
 | ||||
|     enable_irq(); | ||||
|     // Start bus master
 | ||||
|     m_bus_master_base.out<u8>(0x9); | ||||
|     m_io_group.bus_master_base().out<u8>(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<u8>() & ATA_SR_BSY) | ||||
|     while (m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & 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<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_HDDEVSEL).out<u8>(devsel | (static_cast<u8>(slave_request) << 4) | 0x40); | ||||
|     m_io_group.control_base().offset(ATA_CTL_CONTROL).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out<u8>(devsel | (static_cast<u8>(slave_request) << 4) | 0x40); | ||||
|     io_delay(); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_FEATURES).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_FEATURES).out<u8>(0); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA0).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA1).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA2).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>(0); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(request.block_count()); | ||||
|     m_io_base.offset(ATA_REG_LBA0).out<u8>((lba & 0x000000ff) >> 0); | ||||
|     m_io_base.offset(ATA_REG_LBA1).out<u8>((lba & 0x0000ff00) >> 8); | ||||
|     m_io_base.offset(ATA_REG_LBA2).out<u8>((lba & 0x00ff0000) >> 16); | ||||
|     m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(request.block_count()); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>((lba & 0x000000ff) >> 0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>((lba & 0x0000ff00) >> 8); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>((lba & 0x00ff0000) >> 16); | ||||
| 
 | ||||
|     for (;;) { | ||||
|         auto status = m_io_base.offset(ATA_REG_STATUS).in<u8>(); | ||||
|         auto status = m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>(); | ||||
|         if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     enable_irq(); | ||||
|     m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_READ_PIO); | ||||
|     m_io_group.io_base().offset(ATA_REG_COMMAND).out<u8>(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<u8>(0); | ||||
|     m_io_group.bus_master_base().out<u8>(0); | ||||
| 
 | ||||
|     // Write the PRDT location
 | ||||
|     m_bus_master_base.offset(4).out<u32>(m_prdt_page->paddr().get()); | ||||
|     m_io_group.bus_master_base().offset(4).out<u32>(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<u8>(m_bus_master_base.offset(2).in<u8>() | 0x6); | ||||
|     m_io_group.bus_master_base().offset(2).out<u8>(m_io_group.bus_master_base().offset(2).in<u8>() | 0x6); | ||||
| 
 | ||||
|     while (m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) | ||||
|     while (m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) | ||||
|         ; | ||||
| 
 | ||||
|     m_control_base.offset(ATA_CTL_CONTROL).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_HDDEVSEL).out<u8>(0x40 | (static_cast<u8>(slave_request) << 4)); | ||||
|     m_io_group.control_base().offset(ATA_CTL_CONTROL).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out<u8>(0x40 | (static_cast<u8>(slave_request) << 4)); | ||||
|     io_delay(); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_FEATURES).out<u16>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_FEATURES).out<u16>(0); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA0).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA1).out<u8>(0); | ||||
|     m_io_base.offset(ATA_REG_LBA2).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>(0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>(0); | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_SECCOUNT0).out<u8>(request.block_count()); | ||||
|     m_io_base.offset(ATA_REG_LBA0).out<u8>((lba & 0x000000ff) >> 0); | ||||
|     m_io_base.offset(ATA_REG_LBA1).out<u8>((lba & 0x0000ff00) >> 8); | ||||
|     m_io_base.offset(ATA_REG_LBA2).out<u8>((lba & 0x00ff0000) >> 16); | ||||
|     m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(request.block_count()); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>((lba & 0x000000ff) >> 0); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>((lba & 0x0000ff00) >> 8); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>((lba & 0x00ff0000) >> 16); | ||||
| 
 | ||||
|     for (;;) { | ||||
|         auto status = m_io_base.offset(ATA_REG_STATUS).in<u8>(); | ||||
|         auto status = m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>(); | ||||
|         if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_WRITE_DMA_EXT); | ||||
|     m_io_group.io_base().offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_WRITE_DMA_EXT); | ||||
|     io_delay(); | ||||
| 
 | ||||
|     enable_irq(); | ||||
|     // Start bus master
 | ||||
|     m_bus_master_base.out<u8>(0x1); | ||||
|     m_io_group.bus_master_base().out<u8>(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<u8>() & ATA_SR_BSY) || !(m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRQ)) | ||||
|     while ((m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) || !(m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRQ)) | ||||
|         ; | ||||
| 
 | ||||
|     u8 status = m_io_base.offset(ATA_REG_STATUS).in<u8>(); | ||||
|     u8 status = m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>(); | ||||
|     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<u8>() & ATA_SR_BSY) | ||||
|     while (m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & 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<u8>(count == 256 ? 0 : LSB(count)); | ||||
|     m_io_base.offset(ATA_REG_LBA0).out<u8>(start_sector & 0xff); | ||||
|     m_io_base.offset(ATA_REG_LBA1).out<u8>((start_sector >> 8) & 0xff); | ||||
|     m_io_base.offset(ATA_REG_LBA2).out<u8>((start_sector >> 16) & 0xff); | ||||
|     m_io_base.offset(ATA_REG_HDDEVSEL).out<u8>(devsel | ((start_sector >> 24) & 0xf)); | ||||
|     m_io_group.io_base().offset(ATA_REG_SECCOUNT0).out<u8>(count == 256 ? 0 : LSB(count)); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA0).out<u8>(start_sector & 0xff); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA1).out<u8>((start_sector >> 8) & 0xff); | ||||
|     m_io_group.io_base().offset(ATA_REG_LBA2).out<u8>((start_sector >> 16) & 0xff); | ||||
|     m_io_group.io_base().offset(ATA_REG_HDDEVSEL).out<u8>(devsel | ((start_sector >> 24) & 0xf)); | ||||
| 
 | ||||
|     IO::out8(0x3F6, 0x08); | ||||
|     while (!(m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRDY)) | ||||
|     while (!(m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRDY)) | ||||
|         ; | ||||
| 
 | ||||
|     m_io_base.offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_WRITE_PIO); | ||||
|     m_io_group.io_base().offset(ATA_REG_COMMAND).out<u8>(ATA_CMD_WRITE_PIO); | ||||
| 
 | ||||
|     io_delay(); | ||||
|     while ((m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) || !(m_io_base.offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRQ)) | ||||
|     while ((m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_BSY) || !(m_io_group.io_base().offset(ATA_REG_STATUS).in<u8>() & ATA_SR_DRQ)) | ||||
|         ; | ||||
| 
 | ||||
|     enable_irq(); | ||||
|  | @ -41,11 +41,11 @@ | |||
| #include <AK/RefPtr.h> | ||||
| #include <Kernel/Devices/Device.h> | ||||
| #include <Kernel/IO.h> | ||||
| #include <Kernel/Interrupts/IRQHandler.h> | ||||
| #include <Kernel/Lock.h> | ||||
| #include <Kernel/PCI/Access.h> | ||||
| #include <Kernel/PCI/Device.h> | ||||
| #include <Kernel/PhysicalAddress.h> | ||||
| #include <Kernel/Random.h> | ||||
| #include <Kernel/Storage/StorageDevice.h> | ||||
| #include <Kernel/VM/PhysicalPage.h> | ||||
| #include <Kernel/WaitQueue.h> | ||||
| 
 | ||||
|  | @ -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<PATAChannel> 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<PATADiskDevice> master_device() { return m_master; }; | ||||
|     RefPtr<PATADiskDevice> 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<IDEChannel> create(const IDEController&, IOAddressGroup, ChannelType type, bool force_pio); | ||||
|     IDEChannel(const IDEController&, IOAddressGroup, ChannelType type, bool force_pio); | ||||
|     virtual ~IDEChannel() override; | ||||
| 
 | ||||
|     RefPtr<StorageDevice> master_device(); | ||||
|     RefPtr<StorageDevice> 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<PhysicalRegionDescriptor*>(m_prdt_page->paddr().offset(0xc0000000).as_ptr()); } | ||||
|     RefPtr<PhysicalPage> m_prdt_page; | ||||
|     RefPtr<PhysicalPage> m_dma_buffer_page; | ||||
|     IOAddress m_bus_master_base; | ||||
|     Lockable<bool> m_dma_enabled; | ||||
|     EntropySource m_entropy_source; | ||||
| 
 | ||||
|     RefPtr<PATADiskDevice> m_master; | ||||
|     RefPtr<PATADiskDevice> m_slave; | ||||
|     RefPtr<StorageDevice> m_master; | ||||
|     RefPtr<StorageDevice> 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<u8> m_request_lock; | ||||
| 
 | ||||
|     IOAddressGroup m_io_group; | ||||
|     NonnullRefPtr<IDEController> m_parent_controller; | ||||
| }; | ||||
| } | ||||
							
								
								
									
										103
									
								
								Kernel/Storage/IDEController.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								Kernel/Storage/IDEController.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> | ||||
|  * 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 <AK/OwnPtr.h> | ||||
| #include <AK/RefPtr.h> | ||||
| #include <AK/Types.h> | ||||
| #include <Kernel/Storage/IDEController.h> | ||||
| #include <Kernel/Storage/PATADiskDevice.h> | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| NonnullRefPtr<IDEController> 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<StorageDevice> 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; | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										61
									
								
								Kernel/Storage/IDEController.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Kernel/Storage/IDEController.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> | ||||
|  * 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 <AK/OwnPtr.h> | ||||
| #include <AK/RefPtr.h> | ||||
| #include <AK/Types.h> | ||||
| #include <Kernel/Storage/IDEChannel.h> | ||||
| #include <Kernel/Storage/StorageController.h> | ||||
| #include <Kernel/Storage/StorageDevice.h> | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class AsyncBlockDeviceRequest; | ||||
| 
 | ||||
| class IDEController final : public StorageController { | ||||
|     AK_MAKE_ETERNAL | ||||
| public: | ||||
| public: | ||||
|     static NonnullRefPtr<IDEController> initialize(PCI::Address address, bool force_pio); | ||||
|     virtual ~IDEController() override; | ||||
| 
 | ||||
|     virtual RefPtr<StorageDevice> 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<IDEChannel> m_channels; | ||||
| }; | ||||
| } | ||||
							
								
								
									
										78
									
								
								Kernel/Storage/PATADiskDevice.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								Kernel/Storage/PATADiskDevice.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | ||||
|  * 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 <AK/Memory.h> | ||||
| #include <AK/StringView.h> | ||||
| #include <Kernel/FileSystem/FileDescription.h> | ||||
| #include <Kernel/Storage/IDEChannel.h> | ||||
| #include <Kernel/Storage/IDEController.h> | ||||
| #include <Kernel/Storage/PATADiskDevice.h> | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| NonnullRefPtr<PATADiskDevice> 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; | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -30,15 +30,16 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <Kernel/Devices/BlockDevice.h> | ||||
| #include <Kernel/Interrupts/IRQHandler.h> | ||||
| #include <Kernel/Lock.h> | ||||
| #include <Kernel/Storage/StorageDevice.h> | ||||
| 
 | ||||
| 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<PATADiskDevice> create(PATAChannel&, DriveType, int major, int minor); | ||||
|     static NonnullRefPtr<PATADiskDevice> 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<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; | ||||
|     virtual bool can_read(const FileDescription&, size_t) const override; | ||||
|     virtual KResultOr<size_t> 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; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										64
									
								
								Kernel/Storage/StorageController.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Kernel/Storage/StorageController.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> | ||||
|  * 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 <AK/OwnPtr.h> | ||||
| #include <AK/RefPtr.h> | ||||
| #include <Kernel/Devices/Device.h> | ||||
| #include <Kernel/IO.h> | ||||
| #include <Kernel/Lock.h> | ||||
| #include <Kernel/PCI/Access.h> | ||||
| #include <Kernel/PCI/DeviceController.h> | ||||
| #include <Kernel/PhysicalAddress.h> | ||||
| #include <Kernel/Random.h> | ||||
| #include <Kernel/VM/PhysicalPage.h> | ||||
| #include <Kernel/WaitQueue.h> | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class AsyncBlockDeviceRequest; | ||||
| class StorageDevice; | ||||
| class StorageController : public RefCounted<StorageController> | ||||
|     , public PCI::DeviceController { | ||||
|     AK_MAKE_ETERNAL | ||||
| public: | ||||
| protected: | ||||
|     explicit StorageController(PCI::Address address) | ||||
|         : PCI::DeviceController(address) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     virtual RefPtr<StorageDevice> 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; | ||||
| }; | ||||
| } | ||||
|  | @ -1,5 +1,5 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | ||||
|  * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> | ||||
|  * 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 <AK/Memory.h> | ||||
| #include <AK/StringView.h> | ||||
| #include <Kernel/Devices/PATAChannel.h> | ||||
| #include <Kernel/Devices/PATADiskDevice.h> | ||||
| #include <Kernel/FileSystem/FileDescription.h> | ||||
| #include <Kernel/Storage/StorageDevice.h> | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| NonnullRefPtr<PATADiskDevice> 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<StorageController> 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<size_t> PATADiskDevice::read(FileDescription&, size_t offset, UserOrKernelBuffer& outbuf, size_t len) | ||||
| KResultOr<size_t> 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<size_t> 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<size_t> 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<size_t> PATADiskDevice::write(FileDescription&, size_t offset, const UserOrKernelBuffer& inbuf, size_t len) | ||||
| KResultOr<size_t> 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<size_t> 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<size_t> 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()); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										66
									
								
								Kernel/Storage/StorageDevice.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								Kernel/Storage/StorageDevice.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> | ||||
|  * 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 <Kernel/Devices/BlockDevice.h> | ||||
| #include <Kernel/Interrupts/IRQHandler.h> | ||||
| #include <Kernel/Lock.h> | ||||
| #include <Kernel/Storage/StorageController.h> | ||||
| 
 | ||||
| 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<StorageController> controller() const; | ||||
| 
 | ||||
|     // ^BlockDevice
 | ||||
|     virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; | ||||
|     virtual bool can_read(const FileDescription&, size_t) const override; | ||||
|     virtual KResultOr<size_t> 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<StorageController> m_storage_controller; | ||||
|     size_t m_max_addressable_block; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | @ -40,8 +40,6 @@ | |||
| #include <Kernel/Devices/MBRPartitionTable.h> | ||||
| #include <Kernel/Devices/MBVGADevice.h> | ||||
| #include <Kernel/Devices/NullDevice.h> | ||||
| #include <Kernel/Devices/PATAChannel.h> | ||||
| #include <Kernel/Devices/PATADiskDevice.h> | ||||
| #include <Kernel/Devices/RandomDevice.h> | ||||
| #include <Kernel/Devices/SB16.h> | ||||
| #include <Kernel/Devices/SerialDevice.h> | ||||
|  | @ -67,6 +65,8 @@ | |||
| #include <Kernel/RTC.h> | ||||
| #include <Kernel/Random.h> | ||||
| #include <Kernel/Scheduler.h> | ||||
| #include <Kernel/Storage/IDEController.h> | ||||
| #include <Kernel/Storage/PATADiskDevice.h> | ||||
| #include <Kernel/TTY/PTYMultiplexer.h> | ||||
| #include <Kernel/TTY/VirtualConsole.h> | ||||
| #include <Kernel/Tasks/FinalizerTask.h> | ||||
|  | @ -276,8 +276,15 @@ void init_stage2(void*) | |||
|         Processor::halt(); | ||||
|     } | ||||
| 
 | ||||
|     auto pata0 = PATAChannel::create(PATAChannel::ChannelType::Primary, force_pio); | ||||
|     NonnullRefPtr<BlockDevice> root_dev = *pata0->master_device(); | ||||
|     RefPtr<BlockDevice> 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<BlockDevice> root_dev = checked_root_dev.release_nonnull(); | ||||
| 
 | ||||
|     root = root.substring(strlen("/dev/hda"), root.length() - strlen("/dev/hda")); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Liav A
						Liav A