From 5f82d24d5887e2d87100cea1afbab758073d9a5a Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Fri, 28 Mar 2025 09:39:45 +0100 Subject: ahci: WIP - refactor AHCI command engine, fix PRDT setup and LBA logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch begins a major cleanup and enhancement of AHCI I/O handling: - Refactored AHCI command setup logic to prepare FIS and PRDT entries more correctly. - Fixed miscalculation of 48-bit LBA extraction from IDENTIFY response. - Rewrote PRDT loop to increment physical address per entry instead of recomputing offsets. - Replaced read/write/identify branching with unified ternary logic for clarity. - Ensured proper stopping and reinitialization of command engine before issuing commands. - Explicitly remap and zero command list base, FIS base, and command table areas. - Made command slot lookup more robust. - Added fallback wait after command completion to avoid SRBSY/SRDRQ residue. - Dropped misused `YES` flag in read/write call sites — now passed only when needed. Also includes: - Minor cleanup in `BootKit.h` (whitespace). - NeFS debug message clarified to avoid accidental fork overwrites. This is a **work-in-progress** rework of the AHCI path. Next steps will involve: - More robust error recovery. - Support for non-512 sector drives. - Support for multiple ports and NCQ. Signed-off-by: Amlal El Mahrouss --- dev/boot/BootKit/BootKit.h | 2 +- dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc | 102 +++++++++++++++++------- dev/kernel/src/FS/NeFS.cc | 2 +- 3 files changed, 75 insertions(+), 31 deletions(-) (limited to 'dev') diff --git a/dev/boot/BootKit/BootKit.h b/dev/boot/BootKit/BootKit.h index 6cde6a51..d8c33db0 100644 --- a/dev/boot/BootKit/BootKit.h +++ b/dev/boot/BootKit/BootKit.h @@ -41,7 +41,7 @@ namespace Boot { EXTERN void ThrowError(const WideChar* errorCode, const WideChar* reason) noexcept; - + class BootTextWriter; class BootFileReader; class BootThread; diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc index e3be5fb6..7203f19d 100644 --- a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc +++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc @@ -81,10 +81,10 @@ STATIC Void drv_compute_disk_ahci() noexcept rt_set_memory(identify_data, 0, kSzIdent); - /// Send AHCI command. + /// Send AHCI command for identification. drv_std_input_output_ahci(0, identify_data, kAHCISectorSize, kSzIdent); - /// Extract 28-bit LBA. + /// Extract 48-bit LBA. kSATASectorCount = (identify_data[61] << 16) | identify_data[60]; /// Show what we got. @@ -126,7 +126,6 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz if (slot == ~0) { err_global_get() = kErrorDisk; - return; } @@ -136,15 +135,17 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz rt_set_memory(buffer, 0, size_buffer); } + /// prepare command header. volatile HbaCmdHeader* command_header = ((HbaCmdHeader*)(((UInt64)kSATAHba->Ports[kSATAIndex].Clb))); + /// jump to found slot. command_header += slot; MUST_PASS(command_header); command_header->Cfl = sizeof(FisRegH2D) / sizeof(UInt32); command_header->Write = Write; - command_header->Prdtl = (UInt16)((size_buffer - 1) >> 4) + 1; + command_header->Prdtl = (UInt16)((size_buffer - 1) / 8); HbaCmdTbl* command_table = (HbaCmdTbl*)((VoidPtr)((UInt64)command_header->Ctba)); @@ -158,25 +159,19 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz for (; prd_i < (command_header->Prdtl - 1); prd_i++) { - command_table->Prdt[prd_i].Dbc = ((size_buffer / command_header->Prdtl - 1) - 1); - command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys + (prd_i * command_table->Prdt[prd_i].Dbc)); - command_table->Prdt[prd_i].Dbau = (((UInt64)(buffer_phys) >> 32) + (prd_i * command_table->Prdt[prd_i].Dbc)); + command_table->Prdt[prd_i].Dbc = ((command_header->Prdtl - 1) / 8); + command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys); + command_table->Prdt[prd_i].Dbau = (((UInt64)(buffer_phys) >> 32)); command_table->Prdt[prd_i].Ie = YES; - } - command_table->Prdt[prd_i].Dba = ((UInt32)(UInt64)buffer_phys + (prd_i * command_table->Prdt[prd_i].Dbc)); - command_table->Prdt[prd_i].Dbau = (((UInt64)(buffer_phys) >> 32) + (prd_i * command_table->Prdt[prd_i].Dbc)); - command_table->Prdt[prd_i].Dbc = ((size_buffer / command_header->Prdtl - 1) - 1); - command_table->Prdt[prd_i].Ie = YES; + buffer_phys += command_table->Prdt[prd_i].Dbc; + } FisRegH2D* h2d_fis = (FisRegH2D*)(&command_table->Cfis); h2d_fis->FisType = kFISTypeRegH2D; h2d_fis->CmdOrCtrl = CommandOrCTRL; - h2d_fis->Command = Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx; - - if (Identify) - h2d_fis->Command = kAHCICmdIdentify; + h2d_fis->Command = Identify ? (kAHCICmdIdentify) : (Write ? kAHCICmdWriteDmaEx : kAHCICmdReadDmaEx); h2d_fis->Lba0 = (lba)&0xFF; h2d_fis->Lba1 = (lba >> 8) & 0xFF; @@ -210,6 +205,12 @@ STATIC Void drv_std_input_output_ahci(UInt64 lba, UInt8* buffer, SizeT sector_sz } } + /// we should wait again, just in case. + while (kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq)) + { + ; + } + if (kSATAHba->Is & kHBAErrTaskFile) { err_global_get() = kErrorDiskIsCorrupted; @@ -236,25 +237,68 @@ SizeT drv_get_size_ahci() /// @brief Enable Host and probe using the IDENTIFY command. STATIC Void ahci_enable_and_probe() { - if (kSATAHba->Bohc & kHBABohcBiosOwned) + kSATAHba->Ports[kSATAIndex].Cmd &= ~kHBAPxCmdFre; + kSATAHba->Ports[kSATAIndex].Cmd &= ~kHBAPxCmdST; + + while (YES) { - kSATAHba->Bohc |= kHBABohcOSOwned; + if (kSATAHba->Ports[kSATAIndex].Cmd & kHBAPxCmdCR) + continue; - while (kSATAHba->Bohc & kHBABohcBiosOwned) - { - ; - } + if (kSATAHba->Ports[kSATAIndex].Cmd & kHBAPxCmdFR) + continue; + + break; } - // Poll until ready. - while (kSATAHba->Ports[kSATAIndex].Cmd & kHBAPxCmdCR) + // Command engine stopped, remap the AHCI port. + + auto port = &kSATAHba->Ports[kSATAIndex]; + + // Relocate Command List Base. + + constexpr UIntPtr const kAHCIBaseAddress = mib_cast(4); + + port->Clb = kAHCIBaseAddress + (kSATAIndex << 10); + port->Clbu = 0; + + // clean it. + rt_set_memory(reinterpret_cast(port->Clb), 0, 1024); + + // Relocate Frame Info Structure now. + + port->Fb = kAHCIBaseAddress + (kSATAPortCnt << 10) + (kSATAIndex << 10); + port->Fbu = 0; + + // clean it. + rt_set_memory(reinterpret_cast(port->Fb), 0, 256); + + volatile HbaCmdHeader* cmd_hdr = reinterpret_cast(port->Clb); + + for (Int32 i = 0; i < kSATAPortCnt; i++) { - ; + cmd_hdr[i].Prdtl = 8; + cmd_hdr[i].Ctba = kAHCIBaseAddress + (40 << 10) + (kSATAPortCnt << 10) + (kSATAIndex << 10); + cmd_hdr[i].Ctbau = 0; + + rt_set_memory(reinterpret_cast(cmd_hdr[i].Ctba), 0, 256); } + // Now we are ready. + kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdFre; kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdST; + if (kSATAHba->Bohc & kHBABohcBiosOwned) + { + kSATAHba->Bohc |= kHBABohcOSOwned; + + while (kSATAHba->Bohc & kHBABohcBiosOwned) + { + ; + } + } + drv_compute_disk_ahci(); } @@ -377,7 +421,7 @@ namespace NeOS err_global_get() = kErrorSuccess; - drv_std_input_output_ahci(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); + drv_std_input_output_ahci(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); } /// @brief Write AHCI device. @@ -399,7 +443,7 @@ namespace NeOS err_global_get() = kErrorSuccess; - drv_std_input_output_ahci(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); + drv_std_input_output_ahci(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); } } // namespace Detail @@ -434,12 +478,12 @@ namespace NeOS Void drv_std_write(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) { - drv_std_input_output_ahci(lba, (UInt8*)buffer, sector_sz, size_buffer); + drv_std_input_output_ahci(lba, (UInt8*)buffer, sector_sz, size_buffer); } Void drv_std_read(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) { - drv_std_input_output_ahci(lba, (UInt8*)buffer, sector_sz, size_buffer); + drv_std_input_output_ahci(lba, (UInt8*)buffer, sector_sz, size_buffer); } Bool drv_std_init(UInt16& pi) diff --git a/dev/kernel/src/FS/NeFS.cc b/dev/kernel/src/FS/NeFS.cc index 5878067f..29636337 100644 --- a/dev/kernel/src/FS/NeFS.cc +++ b/dev/kernel/src/FS/NeFS.cc @@ -98,7 +98,7 @@ _Output BOOL NeFileSystemParser::CreateFork(_Input NEFS_FORK_STRUCT& the_fork) if (cur_fork.Flags & kNeFSFlagCreated) { - kout << "Error: Fork does exists.\r"; + kout << "Error: Fork does exists, not overwriting this one.\r"; /// sanity check. if (KStringBuilder::Equals(cur_fork.ForkName, the_fork.ForkName) && -- cgit v1.2.3