diff options
| author | Amlal <amlal.elmahrouss@icloud.com> | 2025-01-27 15:09:24 +0100 |
|---|---|---|
| committer | Amlal <amlal.elmahrouss@icloud.com> | 2025-01-27 15:09:24 +0100 |
| commit | a4d64ddc1375f40a4c72bd2ba9326df04058c9bb (patch) | |
| tree | bee09c5cd413151a84183c1ebc8ca81ab7c3c88b /dev/Kernel/HALKit/AMD64/Storage | |
| parent | 974d89be4047f92b9f55e3e8821f4b89c9ab945b (diff) | |
Bump and fixes.
Signed-off-by: Amlal <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'dev/Kernel/HALKit/AMD64/Storage')
| -rw-r--r-- | dev/Kernel/HALKit/AMD64/Storage/ATA-DMA.cc | 38 | ||||
| -rw-r--r-- | dev/Kernel/HALKit/AMD64/Storage/ATA.cc (renamed from dev/Kernel/HALKit/AMD64/Storage/ATA-PIO.cc) | 129 | ||||
| -rw-r--r-- | dev/Kernel/HALKit/AMD64/Storage/SATA.cc (renamed from dev/Kernel/HALKit/AMD64/Storage/SATA-DMA.cc) | 115 |
3 files changed, 146 insertions, 136 deletions
diff --git a/dev/Kernel/HALKit/AMD64/Storage/ATA-DMA.cc b/dev/Kernel/HALKit/AMD64/Storage/ATA-DMA.cc deleted file mode 100644 index 5f765d03..00000000 --- a/dev/Kernel/HALKit/AMD64/Storage/ATA-DMA.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024, Amlal EL Mahrouss, all rights reserved. - -------------------------------------------- */ - -/** - * @file ATA-DMA.cc - * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com) - * @brief ATA driver (DMA mode). - * @version 0.1 - * @date 2024-02-02 - * - * @copyright Copyright (c) Amlal EL Mahrouss - * - */ - -#include <StorageKit/PRDT.h> - -#include <Mod/ATA/ATA.h> -#include <ArchKit/ArchKit.h> - -using namespace Kernel; - -EXTERN_C Int32 kPRDTTransferStatus; -STATIC PRDT kPRDT; - -#ifdef __ATA_DMA__ - -#ifdef __ATA_PIO__ -#error !!! You cant have both PIO and DMA enabled! !!! -#endif /* ifdef __ATA_PIO__ */ - -#ifdef __AHCI__ -#error !!! You cant have both ATA and AHCI enabled! !!! -#endif /* ifdef __AHCI__ */ - -#endif /* ifdef __ATA_DMA__ */ diff --git a/dev/Kernel/HALKit/AMD64/Storage/ATA-PIO.cc b/dev/Kernel/HALKit/AMD64/Storage/ATA.cc index 6e523cb7..a3e8f4ab 100644 --- a/dev/Kernel/HALKit/AMD64/Storage/ATA-PIO.cc +++ b/dev/Kernel/HALKit/AMD64/Storage/ATA.cc @@ -18,7 +18,7 @@ #include <Mod/ATA/ATA.h> #include <ArchKit/ArchKit.h> -#ifdef __ATA_PIO__ +#if defined(__ATA_PIO__) || defined(__ATA_DMA__) using namespace Kernel; using namespace Kernel::HAL; @@ -65,79 +65,130 @@ Void drv_std_select(UInt16 Bus) Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) { UInt16 IO = Bus; - drv_std_select(IO); -ATAInit_Retry: - // Bus init, NEIN bit. - rt_out8(IO + ATA_REG_NEIN, 1); + // Step 1: Wait until drive is not busy + int timeout = 100000; + while ((rt_in8(IO + ATA_REG_STATUS) & ATA_SR_BSY) && --timeout) + ; + if (!timeout) + { + kcout << "Timeout waiting for drive to become ready...\r"; + return false; + } - // identify until it's good + // Step 2: Send IDENTIFY command + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); - auto rdy = rt_in8(IO + ATA_REG_STATUS); + // Step 3: Wait for the drive to be ready (not busy) + drv_std_wait_io(IO); - if (rdy & ATA_SR_ERR) + // Step 4: Check for errors + UInt8 status = rt_in8(IO + ATA_REG_STATUS); + if (status & ATA_SR_ERR) { kcout << "ATA Error, aborting...\r"; - return false; } - if ((rdy & ATA_SR_BSY)) + // Step 5: Read IDENTIFY DEVICE response + for (SizeT indexData = 0UL; indexData < kATADataLen; ++indexData) { - kcout << "Retrying as controller is busy...\r"; - goto ATAInit_Retry; + kATAData[indexData] = rt_in16(IO + ATA_REG_DATA); } - rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); - - /// fetch serial info - /// model, speed, number of sectors... - - drv_std_wait_io(IO); + // Step 6: Set OutBus & OutMaster correctly + OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + OutMaster = (Drive == ATA_MASTER) ? ATA_MASTER : ATA_SLAVE; - for (SizeT indexData = 0ul; indexData < kATADataLen; ++indexData) +#ifdef __ATA_DMA__ + // Step 7: Check if the drive supports DMA + if (!(kATAData[63] & (1 << 8)) || !(kATAData[88] & 0xFF)) { - kATAData[indexData] = rt_in16(IO + ATA_REG_DATA); + kcout << "No DMA support, falling back to PIO...\r"; + return false; // Or switch to PIO mode if needed } - OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + // Step 8: Enable DMA Mode + rt_out8(IO + ATA_REG_FEATURES, 0x03); // Enable DMA mode + rt_out8(IO + ATA_REG_COMMAND, ATA_REG_SET_FEATURES); // Send set features command - OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; + // Step 9: Wait for drive to acknowledge DMA setting + timeout = 100000; + while (!(rt_in8(IO + ATA_REG_STATUS) & ATA_SR_DRDY) && --timeout) + ; + if (!timeout) + { + kcout << "DMA Initialization Timeout...\r"; + return false; + } +#endif // __ATA_DMA__ return YES; } +namespace Details +{ + using namespace Kernel; + + struct __attribute__((packed, aligned(4))) PRD final + { + UInt32 mAddress; + UInt16 mByteCount; + UInt16 mFlags; + }; +} // namespace Details + Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) { Lba /= SectorSz; UInt8 Command = ((!Master) ? 0xE0 : 0xF0); +#ifdef __ATA_PIO__ drv_std_wait_io(IO); +#endif + drv_std_select(IO); rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); - rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz) / SectorSz)); + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + SectorSz - 1) / SectorSz)); rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); - rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); +#ifdef __ATA_PIO__ + rt_out8(ATA_REG_COMMAND, ATA_CMD_READ_PIO); drv_std_wait_io(IO); for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff) { drv_std_wait_io(IO); - Buf[IndexOff] = rt_in16(IO + ATA_REG_DATA); + rt_out16(IO + ATA_REG_DATA, Buf[IndexOff]); drv_std_wait_io(IO); } +#else + if (Size > kib_cast(64)) + ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers."); - drv_std_wait_io(IO); + Details::PRD* prd = (Details::PRD*)mib_cast(4); + prd->mAddress = (UInt32)(UIntPtr)Buf; + prd->mByteCount = Size; + prd->mFlags = 0x8000; + + rt_out32(IO + 0x04, (UInt32)(UIntPtr)prd); + + rt_out8(IO + 0x00, 0x09); // Start DMA engine + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_READ_DMA); + + while (rt_in8(ATA_REG_STATUS) & 0x01) + ; + rt_out8(IO + 0x00, 0x00); // Start DMA engine +#endif // __ATA_PIO__ } Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) @@ -146,19 +197,23 @@ Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorS UInt8 Command = ((!Master) ? 0xE0 : 0xF0); +#ifdef __ATA_PIO__ drv_std_wait_io(IO); +#endif + drv_std_select(IO); rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); - rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + (SectorSz)) / SectorSz)); + rt_out8(IO + ATA_REG_SEC_COUNT0, ((Size + (SectorSz - 1)) / SectorSz)); rt_out8(IO + ATA_REG_LBA0, (Lba) & 0xFF); rt_out8(IO + ATA_REG_LBA1, (Lba) >> 8); rt_out8(IO + ATA_REG_LBA2, (Lba) >> 16); rt_out8(IO + ATA_REG_LBA3, (Lba) >> 24); - rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); +#ifdef __ATA_PIO__ + rt_out8(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); drv_std_wait_io(IO); @@ -168,8 +223,24 @@ Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorS rt_out16(IO + ATA_REG_DATA, Buf[IndexOff]); drv_std_wait_io(IO); } +#else + if (Size > kib_cast(64)) + ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers."); - drv_std_wait_io(IO); + Details::PRD* prd = (Details::PRD*)mib_cast(4); + prd->mAddress = (UInt32)(UIntPtr)Buf; + prd->mByteCount = Size; + prd->mFlags = 0x8000; + + rt_out32(IO + 0x04, (UInt32)(UIntPtr)prd); + + rt_out8(IO + 0x00, 0x09); // Start DMA engine + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_WRITE_DMA); + + while (rt_in8(ATA_REG_STATUS) & 0x01) + ; + rt_out8(IO + 0x00, 0x00); // Start DMA engine +#endif // __ATA_PIO__ } /// @brief is ATA detected? diff --git a/dev/Kernel/HALKit/AMD64/Storage/SATA-DMA.cc b/dev/Kernel/HALKit/AMD64/Storage/SATA.cc index 767f83e5..d2c0ee5b 100644 --- a/dev/Kernel/HALKit/AMD64/Storage/SATA-DMA.cc +++ b/dev/Kernel/HALKit/AMD64/Storage/SATA.cc @@ -15,10 +15,7 @@ * */ -#include "HALKit/AMD64/Processor.h" -#include "KernelKit/DebugOutput.h" -#include "KernelKit/MemoryMgr.h" -#include "NewKit/Defines.h" +#include <stdint.h> #include <KernelKit/UserProcessScheduler.h> #include <KernelKit/LPC.h> @@ -69,17 +66,16 @@ static Kernel::Void drv_calculate_disk_geometry() noexcept Kernel::UInt8 __attribute__((aligned(4096))) identify_data[kib_cast(4)] = {}; - drv_std_input_output<NO, YES, YES>(0, identify_data, 0, kib_cast(8)); + drv_std_input_output<NO, YES, YES>(0, identify_data, 0, kib_cast(4)); - if (!(identify_data[83] & (1 << 10))) - { - kCurrentDiskSectorCount = identify_data[61] << 16; - kCurrentDiskSectorCount |= identify_data[60]; - } - else - { - kCurrentDiskSectorCount = (identify_data[103] << 48) | (identify_data[102] << 32) | (identify_data[101] << 16) | (identify_data[100]); - } + uint32_t lba28_sectors = (identify_data[61] << 16) | identify_data[60]; + + uint64_t lba48_sectors = ((uint64_t)identify_data[103] << 48) | + ((uint64_t)identify_data[102] << 32) | + ((uint64_t)identify_data[101] << 16) | + ((uint64_t)identify_data[100]); + + kCurrentDiskSectorCount = (lba48_sectors) ? lba48_sectors : lba28_sectors; for (Kernel::Int32 i = 0; i < 40; i += 2) { @@ -144,48 +140,23 @@ Kernel::Boolean drv_std_init(Kernel::UInt16& PortsImplemented) kSATAPortIdx = ahci_index; kSATAPort = mem_ahci; - kSATAPort->Ports[kSATAPortIdx].Cmd &= ~kHBAPxCmdST; - kSATAPort->Ports[kSATAPortIdx].Cmd &= ~kHBAPxCmdFre; + // Enable AHCI Mode FIRST + kSATAPort->Ghc |= (1 << 31); - while (YES) + const int timeout = 1000000; + int attempts = 0; + while ((kSATAPort->Ports[kSATAPortIdx].Tfd & 0x80) && (attempts < timeout)) { - if (kSATAPort->Ports[kSATAPortIdx].Cmd & kHBAPxCmdFR) - continue; - if (kSATAPort->Ports[kSATAPortIdx].Cmd & kHBAPxCmdCR) - continue; - - break; + attempts++; } - - const auto kAHCIBaseAddress = mib_cast(4); - - kSATAPort->Ports[kSATAPortIdx].Clb = kAHCIBaseAddress + (kSATAPortIdx << 10); - - rt_set_memory((VoidPtr)((UIntPtr)kSATAPort->Ports[kSATAPortIdx].Clb), 0, 1024); - - kSATAPort->Ports[kSATAPortIdx].Fb = kAHCIBaseAddress + (32 << 10) + (kSATAPortIdx << 8); - kSATAPort->Ports[kSATAPortIdx].Fbu = 0; - - rt_set_memory((VoidPtr)((UIntPtr)kSATAPort->Ports[kSATAPortIdx].Fb), 0, 256); - - HbaCmdHeader* cmd_header = (HbaCmdHeader*)((UIntPtr)kSATAPort->Ports[kSATAPortIdx].Clb); - - for (Int32 i = 0; i < kMaxPortsImplemented; i++) + if (attempts == timeout) { - cmd_header[i].Prdtl = 1; - cmd_header[i].Ctba = kAHCIBaseAddress + (40 << 10) + (kSATAPortIdx << 13) + (i << 8); - - rt_set_memory((VoidPtr)(UIntPtr)cmd_header[i].Ctba, 0, 256); + kcout << "Error: Drive is still busy after waiting.\r"; + return NO; } - while (kSATAPort->Ports[kSATAPortIdx].Cmd & kHBAPxCmdCR) - ; - - kSATAPort->Ports[kSATAPortIdx].Cmd |= kHBAPxCmdFre; kSATAPort->Ports[kSATAPortIdx].Cmd |= kHBAPxCmdST; - - // Enable AHCI Mode FIRST - kSATAPort->Ghc |= (1 >> 31); + kSATAPort->Ports[kSATAPortIdx].Cmd |= kHBAPxCmdFre; drv_calculate_disk_geometry(); @@ -209,12 +180,12 @@ Kernel::Boolean drv_std_detected(Kernel::Void) Kernel::Void drv_std_write(Kernel::UInt64 lba, Kernel::Char* buffer, Kernel::SizeT sector_sz, Kernel::SizeT size_buffer) { - drv_std_input_output<YES, YES, NO>(lba, (Kernel::UInt8*)buffer, sector_sz, size_buffer / sector_sz); + drv_std_input_output<YES, YES, NO>(lba, (Kernel::UInt8*)buffer, sector_sz, size_buffer); } Kernel::Void drv_std_read(Kernel::UInt64 lba, Kernel::Char* buffer, Kernel::SizeT sector_sz, Kernel::SizeT size_buffer) { - drv_std_input_output<NO, YES, NO>(lba, (Kernel::UInt8*)buffer, sector_sz, size_buffer / sector_sz); + drv_std_input_output<NO, YES, NO>(lba, (Kernel::UInt8*)buffer, sector_sz, size_buffer); } static Kernel::Int32 drv_find_cmd_slot(HbaPort* port) noexcept @@ -222,14 +193,14 @@ static Kernel::Int32 drv_find_cmd_slot(HbaPort* port) noexcept if (port == nullptr) return -1; + kcout << "Finding a slot..."; + Kernel::UInt32 slots = (kSATAPort->Ports[kSATAPortIdx].Sact | kSATAPort->Ports[kSATAPortIdx].Ci); for (Kernel::Int32 i = 0; i < ((kSATAPort->Cap & 0x1F) + 1); i++) { - if ((slots & 1) == 0) + if ((slots & (1 << i)) == 0) return i; - - slots >>= 1; } return -1; @@ -250,16 +221,15 @@ static Kernel::Void drv_std_input_output(Kernel::UInt64 lba, Kernel::UInt8* buff kcout << "Reading AHCI disk...\r"; - volatile HbaCmdHeader* command_header = ((volatile HbaCmdHeader*)((Kernel::UInt64)kSATAPort->Ports[kSATAPortIdx].Clb + slot * sizeof(HbaCmdHeader))); - - Kernel::rt_set_memory((void*)command_header, 0, sizeof(HbaCmdTbl)); + volatile HbaCmdHeader* command_header = ((volatile HbaCmdHeader*)((Kernel::UInt64)kSATAPort->Ports[kSATAPortIdx].Clb)); + command_header += slot; MUST_PASS(command_header); command_header->Cfl = sizeof(FisRegH2D) / sizeof(Kernel::UInt32); command_header->Write = Write; - command_header->Prdtl = 1; - command_header->Ctba = (Kernel::UIntPtr)Kernel::mm_new_heap(sizeof(HbaCmdTbl), YES, NO); + command_header->Prdtl = mib_cast(32) / mib_cast(4); + command_header->Prdbc = (1 << slot); volatile HbaCmdTbl* command_table = (volatile HbaCmdTbl*)((Kernel::UInt64)command_header->Ctba); @@ -267,19 +237,22 @@ static Kernel::Void drv_std_input_output(Kernel::UInt64 lba, Kernel::UInt8* buff MUST_PASS(command_table); - command_table->PrdtEntries->Dba = (Kernel::UInt64)buffer; - command_table->PrdtEntries->Dbc = (size_buffer * sector_sz) - 1; - command_table->PrdtEntries->InterruptBit = YES; - kcout << "PRDT Entry 0 - Dba: " << Kernel::hex_number(command_table->PrdtEntries->Dba) << endl; - kcout << "PRDT Entry 0 - Dbc: " << Kernel::hex_number(command_table->PrdtEntries->Dbc) << endl; + command_table->Prdt[0].Dba = (Kernel::UInt32)((Kernel::UInt64)buffer); + command_table->Prdt[0].Dbau = (Kernel::UInt32)(((Kernel::UInt64)buffer >> 32)); + command_table->Prdt[0].Dbc = size_buffer; + command_table->Prdt[0].InterruptBit = YES; // Ensure Interrupt-On-Completion is set - volatile FisRegH2D* h2d_fis = (volatile FisRegH2D*)(command_table->Cfis); + // Debug PRDT entry + kcout << "PRDT Entry - Dba (Low): " << Kernel::hex_number(command_table->Prdt[0].Dba) << endl; + kcout << "PRDT Entry - DbaU (High): " << Kernel::hex_number(command_table->Prdt[0].Dbau) << endl; + kcout << "PRDT Entry - Dbc: " << Kernel::hex_number(command_table->Prdt[0].Dbc) << endl; - Kernel::rt_set_memory((void*)h2d_fis, 0, sizeof(FisRegH2D)); + volatile FisRegH2D* h2d_fis = (volatile FisRegH2D*)(&command_table->Cfis); - h2d_fis->FisType = kFISTypeRegH2D; + Kernel::rt_set_memory((void*)h2d_fis, 0, sizeof(FisRegH2D)); - h2d_fis->CmdOrCtrl = CommandOrCTRL; + h2d_fis->FisType = 0x27; + h2d_fis->CmdOrCtrl = 1; h2d_fis->Command = Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx; @@ -304,6 +277,9 @@ static Kernel::Void drv_std_input_output(Kernel::UInt64 lba, Kernel::UInt8* buff kcout << "waiting for slot to be ready\r\n"; } + Kernel::UInt32 ahci_status = kSATAPort->Ports[kSATAPortIdx].Tfd; + kcout << "AHCI Status Before Write: " << Kernel::hex_number(ahci_status) << endl; + kSATAPort->Ports[kSATAPortIdx].Ci = 1 << slot; while (kSATAPort->Ports[kSATAPortIdx].Ci & (1 << slot)) @@ -314,7 +290,8 @@ static Kernel::Void drv_std_input_output(Kernel::UInt64 lba, Kernel::UInt8* buff kcout << "Last Command Sent: " << (int)Kernel::number(h2d_fis->Command) << endl; - Kernel::mm_delete_heap((Kernel::VoidPtr)command_header->Ctba); + ahci_status = kSATAPort->Ports[kSATAPortIdx].Tfd; + kcout << "AHCI Status Before Write: " << Kernel::hex_number(ahci_status) << endl; } /*** |
