diff --git a/storage/ahci/ahci.cpp b/storage/ahci/ahci.cpp index 54be554c..1ed77aef 100644 --- a/storage/ahci/ahci.cpp +++ b/storage/ahci/ahci.cpp @@ -21,23 +21,27 @@ #include #include -#define ATA_DEV_BUSY 0x80 #define ATA_DEV_DRQ 0x08 -#define ATA_CMD_WRITE_DMA_EX 0x35 +#define ATA_DEV_BUSY 0x80 #define ATA_CMD_READ_DMA_EX 0x25 +#define ATA_CMD_WRITE_DMA_EX 0x35 +#define ATA_CMD_IDENTIFY 0xEC + +#define ATAPI_CMD_IDENTIFY_PACKET 0xA1 + +#define HBA_PORT_IPM_ACTIVE 0x1 +#define HBA_PORT_DEV_PRESENT 0x3 #define HBA_PxIS_TFES (1 << 30) -#define HBA_PORT_DEV_PRESENT 0x3 -#define HBA_PORT_IPM_ACTIVE 0x1 -#define SATA_SIG_ATAPI 0xEB140101 #define SATA_SIG_ATA 0x00000101 -#define SATA_SIG_SEMB 0xC33C0101 #define SATA_SIG_PM 0x96690101 +#define SATA_SIG_SEMB 0xC33C0101 +#define SATA_SIG_ATAPI 0xEB140101 -#define HBA_PxCMD_CR 0x8000 -#define HBA_PxCMD_FRE 0x0010 #define HBA_PxCMD_ST 0x0001 +#define HBA_PxCMD_FRE 0x0010 #define HBA_PxCMD_FR 0x4000 +#define HBA_PxCMD_CR 0x8000 enum PortType { @@ -160,6 +164,402 @@ struct FIS_REG_H2D uint8_t Reserved1[4]; }; +/* https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ata/ns-ata-_identify_device_data */ +struct __attribute__((packed)) ATA_IDENTIFY +{ + struct __attribute__((packed)) + { + uint16_t Reserved1 : 1; + uint16_t Retired3 : 1; + uint16_t ResponseIncomplete : 1; + uint16_t Retired2 : 3; + uint16_t FixedDevice : 1; + uint16_t RemovableMedia : 1; + uint16_t Retired1 : 7; + uint16_t DeviceType : 1; + } GeneralConfiguration; + uint16_t NumCylinders; + uint16_t SpecificConfiguration; + uint16_t NumHeads; + uint16_t Retired1[2]; + uint16_t NumSectorsPerTrack; + uint16_t VendorUnique1[3]; + uint8_t SerialNumber[20]; + uint16_t Retired2[2]; + uint16_t Obsolete1; + uint8_t FirmwareRevision[8]; + uint8_t ModelNumber[40]; + uint8_t MaximumBlockTransfer; + uint8_t VendorUnique2; + struct __attribute__((packed)) + { + uint16_t FeatureSupported : 1; + uint16_t Reserved : 15; + } TrustedComputing; + struct __attribute__((packed)) + { + uint8_t CurrentLongPhysicalSectorAlignment : 2; + uint8_t ReservedByte49 : 6; + uint8_t DmaSupported : 1; + uint8_t LbaSupported : 1; + uint8_t IordyDisable : 1; + uint8_t IordySupported : 1; + uint8_t Reserved1 : 1; + uint8_t StandybyTimerSupport : 1; + uint8_t Reserved2 : 2; + uint16_t ReservedWord50; + } Capabilities; + uint16_t ObsoleteWords51[2]; + uint16_t TranslationFieldsValid : 3; + uint16_t Reserved3 : 5; + uint16_t FreeFallControlSensitivity : 8; + uint16_t NumberOfCurrentCylinders; + uint16_t NumberOfCurrentHeads; + uint16_t CurrentSectorsPerTrack; + uint32_t CurrentSectorCapacity; + uint8_t CurrentMultiSectorSetting; + uint8_t MultiSectorSettingValid : 1; + uint8_t ReservedByte59 : 3; + uint8_t SanitizeFeatureSupported : 1; + uint8_t CryptoScrambleExtCommandSupported : 1; + uint8_t OverwriteExtCommandSupported : 1; + uint8_t BlockEraseExtCommandSupported : 1; + uint32_t UserAddressableSectors; + uint16_t ObsoleteWord62; + uint16_t MultiWordDMASupport : 8; + uint16_t MultiWordDMAActive : 8; + uint16_t AdvancedPIOModes : 8; + uint16_t ReservedByte64 : 8; + uint16_t MinimumMWXferCycleTime; + uint16_t RecommendedMWXferCycleTime; + uint16_t MinimumPIOCycleTime; + uint16_t MinimumPIOCycleTimeIORDY; + struct __attribute__((packed)) + { + uint16_t ZonedCapabilities : 2; + uint16_t NonVolatileWriteCache : 1; + uint16_t ExtendedUserAddressableSectorsSupported : 1; + uint16_t DeviceEncryptsAllUserData : 1; + uint16_t ReadZeroAfterTrimSupported : 1; + uint16_t Optional28BitCommandsSupported : 1; + uint16_t IEEE1667 : 1; + uint16_t DownloadMicrocodeDmaSupported : 1; + uint16_t SetMaxSetPasswordUnlockDmaSupported : 1; + uint16_t WriteBufferDmaSupported : 1; + uint16_t ReadBufferDmaSupported : 1; + uint16_t DeviceConfigIdentifySetDmaSupported : 1; + uint16_t LPSAERCSupported : 1; + uint16_t DeterministicReadAfterTrimSupported : 1; + uint16_t CFastSpecSupported : 1; + } AdditionalSupported; + uint16_t ReservedWords70[5]; + uint16_t QueueDepth : 5; + uint16_t ReservedWord75 : 11; + struct __attribute__((packed)) + { + uint16_t Reserved0 : 1; + uint16_t SataGen1 : 1; + uint16_t SataGen2 : 1; + uint16_t SataGen3 : 1; + uint16_t Reserved1 : 4; + uint16_t NCQ : 1; + uint16_t HIPM : 1; + uint16_t PhyEvents : 1; + uint16_t NcqUnload : 1; + uint16_t NcqPriority : 1; + uint16_t HostAutoPS : 1; + uint16_t DeviceAutoPS : 1; + uint16_t ReadLogDMA : 1; + uint16_t Reserved2 : 1; + uint16_t CurrentSpeed : 3; + uint16_t NcqStreaming : 1; + uint16_t NcqQueueMgmt : 1; + uint16_t NcqReceiveSend : 1; + uint16_t DEVSLPtoReducedPwrState : 1; + uint16_t Reserved3 : 8; + } SerialAtaCapabilities; + struct __attribute__((packed)) + { + uint16_t Reserved0 : 1; + uint16_t NonZeroOffsets : 1; + uint16_t DmaSetupAutoActivate : 1; + uint16_t DIPM : 1; + uint16_t InOrderData : 1; + uint16_t HardwareFeatureControl : 1; + uint16_t SoftwareSettingsPreservation : 1; + uint16_t NCQAutosense : 1; + uint16_t DEVSLP : 1; + uint16_t HybridInformation : 1; + uint16_t Reserved1 : 6; + } SerialAtaFeaturesSupported; + struct __attribute__((packed)) + { + uint16_t Reserved0 : 1; + uint16_t NonZeroOffsets : 1; + uint16_t DmaSetupAutoActivate : 1; + uint16_t DIPM : 1; + uint16_t InOrderData : 1; + uint16_t HardwareFeatureControl : 1; + uint16_t SoftwareSettingsPreservation : 1; + uint16_t DeviceAutoPS : 1; + uint16_t DEVSLP : 1; + uint16_t HybridInformation : 1; + uint16_t Reserved1 : 6; + } SerialAtaFeaturesEnabled; + uint16_t MajorRevision; + uint16_t MinorRevision; + struct __attribute__((packed)) + { + uint16_t SmartCommands : 1; + uint16_t SecurityMode : 1; + uint16_t RemovableMediaFeature : 1; + uint16_t PowerManagement : 1; + uint16_t Reserved1 : 1; + uint16_t WriteCache : 1; + uint16_t LookAhead : 1; + uint16_t ReleaseInterrupt : 1; + uint16_t ServiceInterrupt : 1; + uint16_t DeviceReset : 1; + uint16_t HostProtectedArea : 1; + uint16_t Obsolete1 : 1; + uint16_t WriteBuffer : 1; + uint16_t ReadBuffer : 1; + uint16_t Nop : 1; + uint16_t Obsolete2 : 1; + uint16_t DownloadMicrocode : 1; + uint16_t DmaQueued : 1; + uint16_t Cfa : 1; + uint16_t AdvancedPm : 1; + uint16_t Msn : 1; + uint16_t PowerUpInStandby : 1; + uint16_t ManualPowerUp : 1; + uint16_t Reserved2 : 1; + uint16_t SetMax : 1; + uint16_t Acoustics : 1; + uint16_t BigLba : 1; + uint16_t DeviceConfigOverlay : 1; + uint16_t FlushCache : 1; + uint16_t FlushCacheExt : 1; + uint16_t WordValid83 : 2; + uint16_t SmartErrorLog : 1; + uint16_t SmartSelfTest : 1; + uint16_t MediaSerialNumber : 1; + uint16_t MediaCardPassThrough : 1; + uint16_t StreamingFeature : 1; + uint16_t GpLogging : 1; + uint16_t WriteFua : 1; + uint16_t WriteQueuedFua : 1; + uint16_t WWN64Bit : 1; + uint16_t URGReadStream : 1; + uint16_t URGWriteStream : 1; + uint16_t ReservedForTechReport : 2; + uint16_t IdleWithUnloadFeature : 1; + uint16_t WordValid : 2; + } CommandSetSupport; + struct __attribute__((packed)) + { + uint16_t SmartCommands : 1; + uint16_t SecurityMode : 1; + uint16_t RemovableMediaFeature : 1; + uint16_t PowerManagement : 1; + uint16_t Reserved1 : 1; + uint16_t WriteCache : 1; + uint16_t LookAhead : 1; + uint16_t ReleaseInterrupt : 1; + uint16_t ServiceInterrupt : 1; + uint16_t DeviceReset : 1; + uint16_t HostProtectedArea : 1; + uint16_t Obsolete1 : 1; + uint16_t WriteBuffer : 1; + uint16_t ReadBuffer : 1; + uint16_t Nop : 1; + uint16_t Obsolete2 : 1; + uint16_t DownloadMicrocode : 1; + uint16_t DmaQueued : 1; + uint16_t Cfa : 1; + uint16_t AdvancedPm : 1; + uint16_t Msn : 1; + uint16_t PowerUpInStandby : 1; + uint16_t ManualPowerUp : 1; + uint16_t Reserved2 : 1; + uint16_t SetMax : 1; + uint16_t Acoustics : 1; + uint16_t BigLba : 1; + uint16_t DeviceConfigOverlay : 1; + uint16_t FlushCache : 1; + uint16_t FlushCacheExt : 1; + uint16_t Resrved3 : 1; + uint16_t Words119_120Valid : 1; + uint16_t SmartErrorLog : 1; + uint16_t SmartSelfTest : 1; + uint16_t MediaSerialNumber : 1; + uint16_t MediaCardPassThrough : 1; + uint16_t StreamingFeature : 1; + uint16_t GpLogging : 1; + uint16_t WriteFua : 1; + uint16_t WriteQueuedFua : 1; + uint16_t WWN64Bit : 1; + uint16_t URGReadStream : 1; + uint16_t URGWriteStream : 1; + uint16_t ReservedForTechReport : 2; + uint16_t IdleWithUnloadFeature : 1; + uint16_t Reserved4 : 2; + } CommandSetActive; + uint16_t UltraDMASupport : 8; + uint16_t UltraDMAActive : 8; + struct __attribute__((packed)) + { + uint16_t TimeRequired : 15; + uint16_t ExtendedTimeReported : 1; + } NormalSecurityEraseUnit; + struct __attribute__((packed)) + { + uint16_t TimeRequired : 15; + uint16_t ExtendedTimeReported : 1; + } EnhancedSecurityEraseUnit; + uint16_t CurrentAPMLevel : 8; + uint16_t ReservedWord91 : 8; + uint16_t MasterPasswordID; + uint16_t HardwareResetResult; + uint16_t CurrentAcousticValue : 8; + uint16_t RecommendedAcousticValue : 8; + uint16_t StreamMinRequestSize; + uint16_t StreamingTransferTimeDMA; + uint16_t StreamingAccessLatencyDMAPIO; + uint32_t StreamingPerfGranularity; + uint32_t Max48BitLBA[2]; + uint16_t StreamingTransferTime; + uint16_t DsmCap; + struct __attribute__((packed)) + { + uint16_t LogicalSectorsPerPhysicalSector : 4; + uint16_t Reserved0 : 8; + uint16_t LogicalSectorLongerThan256Words : 1; + uint16_t MultipleLogicalSectorsPerPhysicalSector : 1; + uint16_t Reserved1 : 2; + } PhysicalLogicalSectorSize; + uint16_t InterSeekDelay; + uint16_t WorldWideName[4]; + uint16_t ReservedForWorldWideName128[4]; + uint16_t ReservedForTlcTechnicalReport; + uint16_t WordsPerLogicalSector[2]; + struct __attribute__((packed)) + { + uint16_t ReservedForDrqTechnicalReport : 1; + uint16_t WriteReadVerify : 1; + uint16_t WriteUncorrectableExt : 1; + uint16_t ReadWriteLogDmaExt : 1; + uint16_t DownloadMicrocodeMode3 : 1; + uint16_t FreefallControl : 1; + uint16_t SenseDataReporting : 1; + uint16_t ExtendedPowerConditions : 1; + uint16_t Reserved0 : 6; + uint16_t WordValid : 2; + } CommandSetSupportExt; + struct __attribute__((packed)) + { + uint16_t ReservedForDrqTechnicalReport : 1; + uint16_t WriteReadVerify : 1; + uint16_t WriteUncorrectableExt : 1; + uint16_t ReadWriteLogDmaExt : 1; + uint16_t DownloadMicrocodeMode3 : 1; + uint16_t FreefallControl : 1; + uint16_t SenseDataReporting : 1; + uint16_t ExtendedPowerConditions : 1; + uint16_t Reserved0 : 6; + uint16_t Reserved1 : 2; + } CommandSetActiveExt; + uint16_t ReservedForExpandedSupportandActive[6]; + uint16_t MsnSupport : 2; + uint16_t ReservedWord127 : 14; + struct __attribute__((packed)) + { + uint16_t SecuritySupported : 1; + uint16_t SecurityEnabled : 1; + uint16_t SecurityLocked : 1; + uint16_t SecurityFrozen : 1; + uint16_t SecurityCountExpired : 1; + uint16_t EnhancedSecurityEraseSupported : 1; + uint16_t Reserved0 : 2; + uint16_t SecurityLevel : 1; + uint16_t Reserved1 : 7; + } SecurityStatus; + uint16_t ReservedWord129[31]; + struct __attribute__((packed)) + { + uint16_t MaximumCurrentInMA : 12; + uint16_t CfaPowerMode1Disabled : 1; + uint16_t CfaPowerMode1Required : 1; + uint16_t Reserved0 : 1; + uint16_t Word160Supported : 1; + } CfaPowerMode1; + uint16_t ReservedForCfaWord161[7]; + uint16_t NominalFormFactor : 4; + uint16_t ReservedWord168 : 12; + struct __attribute__((packed)) + { + uint16_t SupportsTrim : 1; + uint16_t Reserved0 : 15; + } DataSetManagementFeature; + uint16_t AdditionalProductID[4]; + uint16_t ReservedForCfaWord174[2]; + uint16_t CurrentMediaSerialNumber[30]; + struct __attribute__((packed)) + { + uint16_t Supported : 1; + uint16_t Reserved0 : 1; + uint16_t WriteSameSuported : 1; + uint16_t ErrorRecoveryControlSupported : 1; + uint16_t FeatureControlSuported : 1; + uint16_t DataTablesSuported : 1; + uint16_t Reserved1 : 6; + uint16_t VendorSpecific : 4; + } SCTCommandTransport; + uint16_t ReservedWord207[2]; + struct __attribute__((packed)) + { + uint16_t AlignmentOfLogicalWithinPhysical : 14; + uint16_t Word209Supported : 1; + uint16_t Reserved0 : 1; + } BlockAlignment; + uint16_t WriteReadVerifySectorCountMode3Only[2]; + uint16_t WriteReadVerifySectorCountMode2Only[2]; + struct __attribute__((packed)) + { + uint16_t NVCachePowerModeEnabled : 1; + uint16_t Reserved0 : 3; + uint16_t NVCacheFeatureSetEnabled : 1; + uint16_t Reserved1 : 3; + uint16_t NVCachePowerModeVersion : 4; + uint16_t NVCacheFeatureSetVersion : 4; + } NVCacheCapabilities; + uint16_t NVCacheSizeLSW; + uint16_t NVCacheSizeMSW; + uint16_t NominalMediaRotationRate; + uint16_t ReservedWord218; + struct __attribute__((packed)) + { + uint8_t NVCacheEstimatedTimeToSpinUpInSeconds; + uint8_t Reserved; + } NVCacheOptions; + uint16_t WriteReadVerifySectorCountMode : 8; + uint16_t ReservedWord220 : 8; + uint16_t ReservedWord221; + struct __attribute__((packed)) + { + uint16_t MajorVersion : 12; + uint16_t TransportType : 4; + } TransportMajorVersion; + uint16_t TransportMinorVersion; + uint16_t ReservedWord224[6]; + uint32_t ExtendedNumberOfUserAddressableSectors[2]; + uint16_t MinBlocksPerDownloadMicrocodeMode03; + uint16_t MaxBlocksPerDownloadMicrocodeMode03; + uint16_t ReservedWord236[19]; + uint16_t Signature : 8; + uint16_t CheckSum : 8; +}; + class Port { public: @@ -167,6 +567,7 @@ public: HBAPort *HBAPortPtr; uint8_t *Buffer; uint8_t PortNumber; + ATA_IDENTIFY *IdentifyData; Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber) { @@ -174,6 +575,8 @@ public: this->HBAPortPtr = PortPtr; this->Buffer = static_cast(AllocateMemory(1)); MemorySet(this->Buffer, 0, PAGE_SIZE); + this->IdentifyData = static_cast(AllocateMemory(1)); + MemorySet(this->IdentifyData, 0, PAGE_SIZE); this->PortNumber = PortNumber; } @@ -229,6 +632,8 @@ public: } this->StartCMD(); + Identify(); + Log("Port %d \"%x %x %x %x\" configured", PortNumber, HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1], HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]); @@ -332,6 +737,75 @@ public: return true; } + + void Identify() + { + MemorySet(this->IdentifyData, 0, sizeof(ATA_IDENTIFY)); + HBACommandHeader *CommandHeader = reinterpret_cast(HBAPortPtr->CommandListBase); + CommandHeader->CommandFISLength = sizeof(FIS_REG_H2D) / sizeof(uint32_t); + CommandHeader->Write = 0; + CommandHeader->PRDTLength = 1; + + HBACommandTable *CommandTable = reinterpret_cast(CommandHeader->CommandTableBaseAddress); + MemorySet(CommandTable, 0, sizeof(HBACommandTable) + (CommandHeader->PRDTLength - 1) * sizeof(HBAPRDTEntry)); + + CommandTable->PRDTEntry[0].DataBaseAddress = (uint32_t)(uint64_t)this->IdentifyData; + CommandTable->PRDTEntry[0].DataBaseAddressUpper = (uint32_t)((uint64_t)this->IdentifyData >> 32); + CommandTable->PRDTEntry[0].ByteCount = 511; + CommandTable->PRDTEntry[0].InterruptOnCompletion = 1; + + FIS_REG_H2D *CommandFIS = (FIS_REG_H2D *)(&CommandTable->CommandFIS); + CommandFIS->FISType = FIS_TYPE_REG_H2D; + CommandFIS->CommandControl = 1; + CommandFIS->Command = this->AHCIPortType == PortType::SATAPI ? ATAPI_CMD_IDENTIFY_PACKET : ATA_CMD_IDENTIFY; + + HBAPortPtr->CommandIssue = 1; + + while (HBAPortPtr->CommandIssue) + Yield(); + + if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES) + { + Log("Error reading IDENTIFY command."); + return; + } + + auto swap = [](uint16_t *data, size_t size) + { + for (size_t i = 0; i < size; i++) + data[i] = (data[i] >> 8) | (data[i] << 8); + }; + + char *Model = (char *)this->IdentifyData->ModelNumber; + char ModelSwap[41]; + for (size_t i = 0; i < 40; i += 2) + { + ModelSwap[i] = Model[i + 1]; + ModelSwap[i + 1] = Model[i]; + } + ModelSwap[40] = 0; + + Log("Port %d \"%s\" identified", PortNumber, + ModelSwap); + Log("Port %d is %s (%d rotation rate)", PortNumber, + IdentifyData->NominalMediaRotationRate == 1 ? "SSD" : "HDD", + IdentifyData->NominalMediaRotationRate); + + if (IdentifyData->Signature != 0xA5) + { + Log("Port %d has no validity signature.", PortNumber); + return; + } + + uint8_t *ptr = (uint8_t *)IdentifyData; + uint8_t sum = 0; + for (size_t i = 0; i < 512; i++) + sum += ptr[i]; + if (sum != 0) + Log("Port %d has invalid checksum.", PortNumber); + else + Log("Port %d has valid checksum.", PortNumber); + } }; Port *Ports[64];