diff options
| author | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2025-03-23 19:13:48 +0100 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2025-03-23 19:15:17 +0100 |
| commit | a13e1c0911c0627184bc38f18c7fdda64447b3ad (patch) | |
| tree | 073a62c09bf216e85a3f310376640fa1805147f9 /dev/kernel/HALKit/AMD64/Storage | |
| parent | 149fa096eb306d03686b3b67e813cf1a78e08cd0 (diff) | |
meta(kernel): Reworked repository's filesystem structure.
Removing useless parts of the project too.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'dev/kernel/HALKit/AMD64/Storage')
| -rw-r--r-- | dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc | 424 | ||||
| -rw-r--r-- | dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc | 253 | ||||
| -rw-r--r-- | dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc | 191 |
3 files changed, 868 insertions, 0 deletions
diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc new file mode 100644 index 00000000..002266de --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc @@ -0,0 +1,424 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss Corporation, all rights reserved. + +------------------------------------------- */ + +/** + * @file AHCI.cc + * @author Amlal El Mahrouss (amlalelmahrouss@icloud.com) + * @brief AHCI driver. + * @version 0.1 + * @date 2024-02-02 + * + * @copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + * + */ + +#include <KernelKit/DeviceMgr.h> +#include <KernelKit/DriveMgr.h> +#include <KernelKit/UserProcessScheduler.h> +#include <KernelKit/LPC.h> + +#include <FirmwareKit/EPM.h> + +#include <modules/ATA/ATA.h> +#include <modules/AHCI/AHCI.h> +#include <KernelKit/PCI/Iterator.h> +#include <NewKit/Utils.h> +#include <KernelKit/LockDelegate.h> + +#include <StorageKit/AHCI.h> + +#define kHBAErrTaskFile (1 << 30) +#define kHBAPxCmdST (0x0001) +#define kHBAPxCmdFre (0x0010) +#define kHBAPxCmdFR (0x4000) +#define kHBAPxCmdCR (0x8000) + +#define kSATALBAMode (1 << 6) + +#define kSATASRBsy (0x80) +#define kSATASRDrq (0x08) + +#define kHBABohcBiosOwned (1 << 0) +#define kHBABohcOSOwned (1 << 1) + +#define kSATAPortCnt (0x20) + +#define kSATASig (0x00000101) +#define kSATAPISig (0xEB140101) + +#define kSATAProgIfAHCI (0x01) +#define kSATASubClass (0x06) +#define kSATABar5 (0x24) + +using namespace NeOS; + +STATIC PCI::Device kSATADev; +STATIC HbaMem* kSATAHba; +STATIC Lba kSATASectorCount = 0UL; +STATIC UInt16 kSATAIndex = 0U; +STATIC Char kCurrentDiskModel[50] = {"UNKNOWN AHCI DRIVE"}; +STATIC UInt16 kSATAPortsImplemented = 0U; + +template <BOOL Write, BOOL CommandOrCTRL, BOOL Identify> +STATIC Void drv_std_input_output(UInt64 lba, UInt8* buffer, SizeT sector_sz, SizeT size_buffer) noexcept; + +STATIC Int32 drv_find_cmd_slot(HbaPort* port) noexcept; + +STATIC Void drv_compute_disk_ahci() noexcept; + +STATIC Void drv_compute_disk_ahci() noexcept +{ + kSATASectorCount = 0UL; + + const UInt16 kSzIdent = kib_cast(1); + + UInt8 identify_data[kSzIdent] = {0}; + + rt_set_memory(identify_data, 0, kSzIdent); + + drv_std_input_output<NO, YES, YES>(0, identify_data, kAHCISectorSize, kSzIdent); + + kSATASectorCount = (identify_data[61] << 16) | identify_data[60]; + + kout << "Disk Model: " << kCurrentDiskModel << kendl; + kout << "Disk Size: " << number(drv_get_size()) << kendl; + kout << "Disk Sector Count: " << number(kSATASectorCount) << kendl; +} + +STATIC Int32 drv_find_cmd_slot(HbaPort* port) noexcept +{ + UInt32 slots = (port->Sact | port->Ci); + + for (Int32 i = 0; i < kSATAPortCnt; ++i) + { + if ((slots & 1) == 0) + return i; + + slots >>= 1; + } + + return ~0; +} + +template <BOOL Write, BOOL CommandOrCTRL, BOOL Identify> +STATIC Void drv_std_input_output(UInt64 lba, UInt8* buffer, SizeT sector_sz, SizeT size_buffer) noexcept +{ + UIntPtr slot = 0UL; + + slot = drv_find_cmd_slot(&kSATAHba->Ports[kSATAIndex]); + + if (slot == ~0) + return; + + volatile HbaCmdHeader* command_header = ((HbaCmdHeader*)(((UInt64)kSATAHba->Ports[kSATAIndex].Clb))); + + 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; + + HbaCmdTbl* command_table = (HbaCmdTbl*)((VoidPtr)((UInt64)command_header->Ctba)); + + rt_set_memory(command_table, 0, sizeof(HbaCmdTbl) + (command_header->Prdtl - 1) * sizeof(HbaPrdtEntry)); + + MUST_PASS(command_table); + + UIntPtr buffer_phys = HAL::hal_get_phys_address(buffer); + + UInt16 prd_i = 0; + + 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].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; + + 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->Lba0 = (lba)&0xFF; + h2d_fis->Lba1 = (lba >> 8) & 0xFF; + h2d_fis->Lba2 = (lba >> 16) & 0xFF; + + h2d_fis->Device = Identify ? 0U : kSATALBAMode; + + h2d_fis->Lba3 = (lba >> 24) & 0xFF; + h2d_fis->Lba4 = (lba >> 32) & 0xFF; + h2d_fis->Lba5 = (lba >> 40) & 0xFF; + + h2d_fis->CountLow = (size_buffer)&0xFF; + h2d_fis->CountHigh = (size_buffer >> 8) & 0xFF; + + while (kSATAHba->Ports[kSATAIndex].Tfd & (kSATASRBsy | kSATASRDrq)) + { + ; + } + + kSATAHba->Ports[kSATAIndex].Ci = (1 << slot); + + while (YES) + { + if (!(kSATAHba->Ports[kSATAIndex].Ci & (1 << slot))) + break; + + if (kSATAHba->Is & kHBAErrTaskFile) + { + err_global_get() = kErrorDiskIsCorrupted; + return; + } + } + + if (kSATAHba->Is & kHBAErrTaskFile) + { + err_global_get() = kErrorDiskIsCorrupted; + return; + } +} + +/*** + @brief Gets the number of sectors inside the drive. + @return Sector size in bytes. + */ +SizeT drv_get_sector_count_ahci() +{ + return kSATASectorCount; +} + +/// @brief Get the drive size. +/// @return Disk size in bytes. +SizeT drv_get_size_ahci() +{ + return drv_get_sector_count() * kAHCISectorSize; +} + +/// @brief Enable Host and probe using the IDENTIFY command. +STATIC Void ahci_enable_and_probe() +{ + if (kSATAHba->Bohc & kHBABohcBiosOwned) + { + kSATAHba->Bohc |= kHBABohcOSOwned; + + while (kSATAHba->Bohc & kHBABohcBiosOwned) + { + ; + } + } + + // Poll until ready. + while (kSATAHba->Ports[kSATAIndex].Cmd & kHBAPxCmdCR) + { + ; + } + + kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdFre; + kSATAHba->Ports[kSATAIndex].Cmd |= kHBAPxCmdST; + + drv_compute_disk_ahci(); +} + +/// @brief Initializes an AHCI disk. +/// @param pi the amount of ports that have been detected. +/// @param atapi reference value, tells whether we should detect ATAPI instead of SATA. +/// @return if the disk was successfully initialized or not. +STATIC Bool drv_std_init_ahci(UInt16& pi, BOOL& atapi) +{ + PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController); + + for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) + { + kSATADev = iterator[device_index].Leak(); // Leak device. + + if (kSATADev.Subclass() == kSATASubClass && + kSATADev.ProgIf() == kSATAProgIfAHCI) + { + HbaMem* mem_ahci = (HbaMem*)kSATADev.Bar(kSATABar5); + + kSATADev.EnableMmio((UIntPtr)mem_ahci); + kSATADev.BecomeBusMaster((UIntPtr)mem_ahci); + + UInt32 ports_implemented = mem_ahci->Pi; + UInt16 ahci_index = 0; + + pi = ports_implemented; + + const UInt16 kMaxPortsImplemented = kSATAPortCnt; + const UInt32 kSATASignature = kSATASig; + const UInt32 kSATAPISignature = kSATAPISig; + const UInt8 kSATAPresent = 0x03; + const UInt8 kSATAIPMActive = 0x01; + + kSATAHba = mem_ahci; + + while (ports_implemented) + { + UInt8 ipm = (mem_ahci->Ports[ahci_index].Ssts >> 8) & 0x0F; + UInt8 det = mem_ahci->Ports[ahci_index].Ssts & 0x0F; + + if (det != kSATAPresent || ipm != kSATAIPMActive) + continue; + + if (mem_ahci->Ports[ahci_index].Sig == kSATASignature) + { + kout << "Detect: /dev/sat" << number(ahci_index) << kendl; + + kSATAIndex = ahci_index; + kSATAHba = mem_ahci; + + ahci_enable_and_probe(); + + break; + } + else if (atapi && kSATAPISignature == mem_ahci->Ports[ahci_index].Sig) + { + kout << "Detect: /dev/atp" << number(ahci_index) << kendl; + + kSATAIndex = ahci_index; + kSATAHba = mem_ahci; + + ahci_enable_and_probe(); + + break; + } + + ports_implemented >>= 1; + ++ahci_index; + } + + return YES; + } + } + + return NO; +} + +Bool drv_std_detected_ahci() +{ + return kSATADev.DeviceId() != (UShort)PCI::PciConfigKind::Invalid && kSATADev.Bar(kSATABar5) != 0; +} + +namespace NeOS +{ + UInt16 sk_init_ahci_device(BOOL atapi) + { + UInt16 pi = 0; + return drv_std_init_ahci(pi, atapi); + + kSATAPortsImplemented = pi; + + return pi; + } + + namespace Detail + { + /// @brief Read AHCI device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_read_ahci(IDeviceObject<MountpointInterface*>* self, MountpointInterface* mnt) + { + AHCIDeviceInterface* dev = (AHCIDeviceInterface*)self; + + if (!dev) + return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) + return; + + drv_std_input_output<NO, YES, NO>(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); + } + + /// @brief Write AHCI device. + /// @param self device + /// @param mnt mounted disk. + STATIC Void sk_io_write_ahci(IDeviceObject<MountpointInterface*>* self, MountpointInterface* mnt) + { + AHCIDeviceInterface* dev = (AHCIDeviceInterface*)self; + + if (!dev) + return; + + auto disk = mnt->GetAddressOf(dev->GetIndex()); + + if (!disk) + return; + + drv_std_input_output<YES, YES, NO>(disk->fPacket.fPacketLba, (UInt8*)disk->fPacket.fPacketContent, kAHCISectorSize, disk->fPacket.fPacketSize); + } + } // namespace Detail + + ErrorOr<AHCIDeviceInterface> sk_acquire_ahci_device(Int32 drv_index) + { + if (!drv_std_detected_ahci()) + return ErrorOr<AHCIDeviceInterface>(kErrorDisk); + + AHCIDeviceInterface device(Detail::sk_io_read_ahci, + Detail::sk_io_write_ahci, + nullptr); + + device.SetPortsImplemented(kSATAPortsImplemented); + device.SetIndex(drv_index); + + return ErrorOr<AHCIDeviceInterface>(device); + } +} // namespace NeOS + +#ifdef __AHCI__ + +Void drv_std_write(UInt64 lba, Char* buffer, SizeT sector_sz, SizeT size_buffer) +{ + drv_std_input_output<YES, YES, NO>(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<NO, YES, NO>(lba, (UInt8*)buffer, sector_sz, size_buffer); +} + +Bool drv_std_init(UInt16& pi) +{ + BOOL atapi = NO; + return drv_std_init_ahci(pi, atapi); +} + +Bool drv_std_detected(Void) +{ + return drv_std_detected_ahci(); +} + +/*** + @brief Gets the number of sectors inside the drive. + @return Sector size in bytes. + */ +SizeT drv_get_sector_count() +{ + return drv_get_sector_count_ahci(); +} + +/// @brief Get the drive size. +/// @return Disk size in bytes. +SizeT drv_get_size() +{ + return drv_get_size_ahci(); +} + +#endif // ifdef __AHCI__ diff --git a/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc new file mode 100644 index 00000000..e025d24d --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/DMA+Generic.cc @@ -0,0 +1,253 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/** + * @file ATA-PIO.cc + * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com) + * @brief ATA driver (PIO mode). + * @version 0.1 + * @date 2024-02-02 + * + * @copyright Copyright (c) Amlal EL Mahrouss + * + */ + +#include <modules/ATA/ATA.h> +#include <ArchKit/ArchKit.h> +#include <KernelKit/PCI/Iterator.h> + +#if defined(__ATA_DMA__) + +#define kATADataLen (256) + +using namespace NeOS; +using namespace NeOS::HAL; + +/// BUGS: 0 + +STATIC Boolean kATADetected = false; +STATIC Int32 kATADeviceType = kATADeviceCount; +STATIC Char kATAData[kATADataLen] = {0}; +STATIC NeOS::PCI::Device kATADevice; +STATIC Char kCurrentDiskModel[50] = {"UNKNOWN DMA DRIVE"}; + +Boolean drv_std_wait_io(UInt16 IO) +{ + for (int i = 0; i < 400; i++) + rt_in8(IO + ATA_REG_STATUS); + +ATAWaitForIO_Retry: + auto status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if ((status_rdy & ATA_SR_BSY)) + goto ATAWaitForIO_Retry; + +ATAWaitForIO_Retry2: + status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (status_rdy & ATA_SR_ERR) + return false; + + if (!(status_rdy & ATA_SR_DRDY)) + goto ATAWaitForIO_Retry2; + + return true; +} + +Void drv_std_select(UInt16 Bus) +{ + if (Bus == ATA_PRIMARY_IO) + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); + else + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); +} + +Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) +{ + PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController); + + for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) + { + kATADevice = iterator[device_index].Leak(); // And then leak the reference. + + // if SATA and then interface is AHCI... + if (kATADevice.Subclass() == 0x01) + { + UInt16 IO = Bus; + + drv_std_select(IO); + + // Bus init, NEIN bit. + rt_out8(IO + ATA_REG_NEIN, 1); + + // identify until it's good. + ATAInit_Retry: + auto status_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (status_rdy & ATA_SR_ERR) + { + return false; + } + + if ((status_rdy & ATA_SR_BSY)) + goto ATAInit_Retry; + + rt_out8(IO + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + + /// fetch serial info + /// model, speed, number of sectors... + + drv_std_wait_io(IO); + + for (SizeT i = 0ul; i < kATADataLen; ++i) + { + drv_std_wait_io(IO); + kATAData[i] = NeOS::HAL::rt_in16(IO + ATA_REG_DATA); + drv_std_wait_io(IO); + } + + for (SizeT i = 0; i < 40; i += 2) + { + kCurrentDiskModel[i * 2] = kATAData[27 + i * 2] >> 8; + kCurrentDiskModel[i * 2 + 1] = kATAData[27 + i * 2] & 0xFF; + } + + kCurrentDiskModel[40] = '\0'; + + kout << "Drive Model: " << kCurrentDiskModel << kendl; + + OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; + + return YES; + } + } + + ke_panic(RUNTIME_CHECK_BOOTSTRAP, "Invalid ATA DMA driver, not detected"); + + return NO; +} + +namespace Detail +{ + using namespace NeOS; + + struct PRDEntry + { + UInt32 mAddress; + UInt16 mByteCount; + UInt16 mFlags; + }; +} // namespace Detail + +static UIntPtr kReadAddr = mib_cast(2); +static UIntPtr kWriteAddr = mib_cast(4); + +Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + if (Size > kib_cast(64)) + ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers."); + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + rt_copy_memory((VoidPtr)Buf, (VoidPtr)kReadAddr, Size); + + drv_std_select(IO); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + 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); + + Detail::PRDEntry* prd = (Detail::PRDEntry*)(kATADevice.Bar(0x20) + 4); // The PRDEntry is not correct. + + prd->mAddress = (UInt32)(UIntPtr)kReadAddr; + prd->mByteCount = Size - 1; + prd->mFlags = 0x8000; // indicate the end of prd. + + rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32)(UIntPtr)prd); + + rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_READ_DMA); + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x09); // Start DMA engine + + while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01) + ; + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine + + rt_copy_memory((VoidPtr)kReadAddr, (VoidPtr)Buf, Size); + + delete prd; + prd = nullptr; +} + +Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + if (Size > kib_cast(64)) + ke_panic(RUNTIME_CHECK_FAILED, "ATA-DMA only supports < 64kb DMA transfers."); + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + rt_copy_memory((VoidPtr)Buf, (VoidPtr)kWriteAddr, Size); + + rt_out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + 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); + + Detail::PRDEntry* prd = (Detail::PRDEntry*)(kATADevice.Bar(0x20) + 4); + prd->mAddress = (UInt32)(UIntPtr)kWriteAddr; + prd->mByteCount = Size - 1; + prd->mFlags = 0x8000; + + rt_out32(kATADevice.Bar(0x20) + 0x04, (UInt32)(UIntPtr)prd); + rt_out8(kATADevice.Bar(0x20) + ATA_REG_COMMAND, ATA_CMD_WRITE_DMA); + + rt_out8(IO + 0x00, 0x09); // Start DMA engine + + while (rt_in8(kATADevice.Bar(0x20) + ATA_REG_STATUS) & 0x01) + ; + + rt_out8(kATADevice.Bar(0x20) + 0x00, 0x00); // Stop DMA engine + + delete prd; + prd = nullptr; +} + +/// @brief is ATA detected? +Boolean drv_std_detected(Void) +{ + return kATADetected; +} + +/*** + @brief Getter, gets the number of sectors inside the drive. +*/ +NeOS::SizeT drv_get_sector_count() +{ + return (kATAData[61] << 16) | kATAData[60]; +} + +/// @brief Get the drive size. +NeOS::SizeT drv_get_size() +{ + return (drv_get_sector_count()) * kATASectorSize; +} + +#endif /* ifdef __ATA_DMA__ */ diff --git a/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc new file mode 100644 index 00000000..cb629478 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc @@ -0,0 +1,191 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal EL Mahrouss, all rights reserved. + +------------------------------------------- */ + +/** + * @file PIO.cc + * @author Amlal EL Mahrouss (amlalelmahrouss@icloud.com) + * @brief ATA driver (PIO mode). + * @version 0.1 + * @date 2024-02-02 + * + * @copyright Copyright (c) Amlal EL Mahrouss + * + */ + +#include <modules/ATA/ATA.h> +#include <ArchKit/ArchKit.h> + +#ifdef __ATA_PIO__ + +using namespace NeOS; +using namespace NeOS::HAL; + +/// BUGS: 0 + +#define kATADataLen 512 + +STATIC Boolean kATADetected = false; +STATIC Int32 kATADeviceType = kATADeviceCount; +STATIC Char kATAData[kATADataLen] = {0}; +STATIC Char kCurrentDiskModel[50] = {"UNKNOWN PIO DRIVE"}; + +Boolean drv_std_wait_io(UInt16 IO) +{ + for (int i = 0; i < 400; i++) + rt_in8(IO + ATA_REG_STATUS); + +ATAWaitForIO_Retry: + auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if ((stat_rdy & ATA_SR_BSY)) + goto ATAWaitForIO_Retry; + +ATAWaitForIO_Retry2: + stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (stat_rdy & ATA_SR_ERR) + return false; + + if (!(stat_rdy & ATA_SR_DRDY)) + goto ATAWaitForIO_Retry2; + + return true; +} + +Void drv_std_select(UInt16 Bus) +{ + if (Bus == ATA_PRIMARY_IO) + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); + else + rt_out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); +} + +Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) +{ + UInt16 IO = Bus; + + drv_std_select(IO); + + // Bus init, NEIN bit. + rt_out8(IO + ATA_REG_NEIN, 1); + + // identify until it's good. +ATAInit_Retry: + auto stat_rdy = rt_in8(IO + ATA_REG_STATUS); + + if (stat_rdy & ATA_SR_ERR) + { + return false; + } + + if ((stat_rdy & ATA_SR_BSY)) + goto ATAInit_Retry; + + OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; + + rt_out8(OutBus + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + + drv_std_wait_io(IO); + + /// fetch serial info + /// model, speed, number of sectors... + + for (SizeT i = 0ul; i < kATADataLen; ++i) + { + kATAData[i] = HAL::rt_in16(OutBus + ATA_REG_DATA); + } + + for (Int32 i = 0; i < 20; i++) + { + kCurrentDiskModel[i * 2] = kATAData[27 + i] >> 8; + kCurrentDiskModel[i * 2 + 1] = kATAData[27 + i + 1] & 0xFF; + } + + kCurrentDiskModel[40] = '\0'; + + kout << "Detect: /dev/ata0" << kendl; + + kout << "Drive Model: " << kCurrentDiskModel << kendl; + + return true; +} + +Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + drv_std_wait_io(IO); + 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_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); + + for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff) + { + drv_std_wait_io(IO); + Buf[IndexOff] = HAL::rt_in16(IO + ATA_REG_DATA); + } +} + +Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + Lba /= SectorSz; + + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + drv_std_wait_io(IO); + 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_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); + + for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff) + { + drv_std_wait_io(IO); + rt_out16(IO + ATA_REG_DATA, Buf[IndexOff]); + } +} + +/// @brief is ATA detected? +Boolean drv_std_detected(Void) +{ + return kATADetected; +} + +/*** + @brief Getter, gets the number of sectors inside the drive. + */ +SizeT drv_get_sector_count() +{ + return (kATAData[61] << 16) | kATAData[60]; +} + +/// @brief Get the drive size. +SizeT drv_get_size() +{ + return (drv_get_sector_count()) * kATASectorSize; +} + +#endif /* ifdef __ATA_PIO__ */
\ No newline at end of file |
