X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=SecurityPkg%2FTcg%2FOpal%2FOpalPassword%2FOpalAhciMode.c;fp=SecurityPkg%2FTcg%2FOpal%2FOpalPassword%2FOpalAhciMode.c;h=0000000000000000000000000000000000000000;hb=a3efbc29c45183fe69bcb311c2d974ddc4e7c00a;hp=0c4edd5346c456cfc7e89eb3f2ee1c6368a9117f;hpb=b6de92f74eca0f36461a5b96117b1428772e2278;p=mirror_edk2.git diff --git a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c b/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c deleted file mode 100644 index 0c4edd5346..0000000000 --- a/SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c +++ /dev/null @@ -1,1282 +0,0 @@ -/** @file - This driver is used for Opal Password Feature support at AHCI mode. - -Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - - -#include "OpalPasswordPei.h" - -/** - Start command for give slot on specific port. - - @param AhciBar AHCI bar address. - @param Port The number of port. - @param CommandSlot The number of CommandSlot. - @param Timeout The timeout Value of start. - - @retval EFI_DEVICE_ERROR The command start unsuccessfully. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_SUCCESS The command start successfully. - -**/ -EFI_STATUS -EFIAPI -AhciStartCommand ( - IN UINT32 AhciBar, - IN UINT8 Port, - IN UINT8 CommandSlot, - IN UINT64 Timeout - ); - -/** - Stop command running for giving port - - @param AhciBar AHCI bar address. - @param Port The number of port. - @param Timeout The timeout Value of stop. - - @retval EFI_DEVICE_ERROR The command stop unsuccessfully. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_SUCCESS The command stop successfully. - -**/ -EFI_STATUS -EFIAPI -AhciStopCommand ( - IN UINT32 AhciBar, - IN UINT8 Port, - IN UINT64 Timeout - ); - -/** - Read AHCI Operation register. - - @param AhciBar AHCI bar address. - @param Offset The operation register offset. - - @return The register content read. - -**/ -UINT32 -EFIAPI -AhciReadReg ( - IN UINT32 AhciBar, - IN UINT32 Offset - ) -{ - UINT32 Data; - - Data = 0; - - Data = MmioRead32 (AhciBar + Offset); - - return Data; -} - -/** - Write AHCI Operation register. - - @param AhciBar AHCI bar address. - @param Offset The operation register offset. - @param Data The Data used to write down. - -**/ -VOID -EFIAPI -AhciWriteReg ( - IN UINT32 AhciBar, - IN UINT32 Offset, - IN UINT32 Data - ) -{ - MmioWrite32 (AhciBar + Offset, Data); - - return ; -} - -/** - Do AND operation with the Value of AHCI Operation register. - - @param AhciBar AHCI bar address. - @param Offset The operation register offset. - @param AndData The Data used to do AND operation. - -**/ -VOID -EFIAPI -AhciAndReg ( - IN UINT32 AhciBar, - IN UINT32 Offset, - IN UINT32 AndData - ) -{ - UINT32 Data; - - Data = AhciReadReg (AhciBar, Offset); - - Data &= AndData; - - AhciWriteReg (AhciBar, Offset, Data); -} - -/** - Do OR operation with the Value of AHCI Operation register. - - @param AhciBar AHCI bar address. - @param Offset The operation register offset. - @param OrData The Data used to do OR operation. - -**/ -VOID -EFIAPI -AhciOrReg ( - IN UINT32 AhciBar, - IN UINT32 Offset, - IN UINT32 OrData - ) -{ - UINT32 Data; - - Data = AhciReadReg (AhciBar, Offset); - - Data |= OrData; - - AhciWriteReg (AhciBar, Offset, Data); -} - -/** - Wait for memory set to the test Value. - - @param AhciBar AHCI bar address. - @param Offset The memory offset to test. - @param MaskValue The mask Value of memory. - @param TestValue The test Value of memory. - @param Timeout The time out Value for wait memory set. - - @retval EFI_DEVICE_ERROR The memory is not set. - @retval EFI_TIMEOUT The memory setting is time out. - @retval EFI_SUCCESS The memory is correct set. - -**/ -EFI_STATUS -EFIAPI -AhciWaitMmioSet ( - IN UINT32 AhciBar, - IN UINT32 Offset, - IN UINT32 MaskValue, - IN UINT32 TestValue, - IN UINT64 Timeout - ) -{ - UINT32 Value; - UINT32 Delay; - - Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1); - - do { - Value = AhciReadReg (AhciBar, Offset) & MaskValue; - - if (Value == TestValue) { - return EFI_SUCCESS; - } - - // - // Stall for 100 microseconds. - // - MicroSecondDelay (100); - - Delay--; - - } while (Delay > 0); - - return EFI_TIMEOUT; -} -/** - Wait for the Value of the specified system memory set to the test Value. - - @param Address The system memory address to test. - @param MaskValue The mask Value of memory. - @param TestValue The test Value of memory. - @param Timeout The time out Value for wait memory set, uses 100ns as a unit. - - @retval EFI_TIMEOUT The system memory setting is time out. - @retval EFI_SUCCESS The system memory is correct set. - -**/ -EFI_STATUS -EFIAPI -AhciWaitMemSet ( - IN EFI_PHYSICAL_ADDRESS Address, - IN UINT32 MaskValue, - IN UINT32 TestValue, - IN UINT64 Timeout - ) -{ - UINT32 Value; - UINT32 Delay; - - Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1); - - do { - // - // Access sytem memory to see if the Value is the tested one. - // - // The system memory pointed by Address will be updated by the - // SATA Host Controller, "volatile" is introduced to prevent - // compiler from optimizing the access to the memory address - // to only read once. - // - Value = *(volatile UINT32 *) (UINTN) Address; - Value &= MaskValue; - - if (Value == TestValue) { - return EFI_SUCCESS; - } - - // - // Stall for 100 microseconds. - // - MicroSecondDelay (100); - - Delay--; - - } while (Delay > 0); - - return EFI_TIMEOUT; -} - -/** - Check the memory status to the test Value. - - @param[in] Address The memory address to test. - @param[in] MaskValue The mask Value of memory. - @param[in] TestValue The test Value of memory. - @param[in, out] RetryTimes The retry times Value for waitting memory set. If 0, then just try once. - - @retval EFI_NOTREADY The memory is not set. - @retval EFI_TIMEOUT The memory setting retry times out. - @retval EFI_SUCCESS The memory is correct set. - -**/ -EFI_STATUS -EFIAPI -AhciCheckMemSet ( - IN UINTN Address, - IN UINT32 MaskValue, - IN UINT32 TestValue, - IN OUT UINTN *RetryTimes OPTIONAL - ) -{ - UINT32 Value; - - if (RetryTimes != NULL) { - (*RetryTimes)--; - } - - Value = *(volatile UINT32 *) Address; - Value &= MaskValue; - - if (Value == TestValue) { - return EFI_SUCCESS; - } - - if ((RetryTimes != NULL) && (*RetryTimes == 0)) { - return EFI_TIMEOUT; - } else { - return EFI_NOT_READY; - } -} - -/** - Clear the port interrupt and error status. It will also clear - HBA interrupt status. - - @param AhciBar AHCI bar address. - @param Port The number of port. - -**/ -VOID -EFIAPI -AhciClearPortStatus ( - IN UINT32 AhciBar, - IN UINT8 Port - ) -{ - UINT32 Offset; - - // - // Clear any error status - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR; - AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset)); - - // - // Clear any port interrupt status - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS; - AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset)); - - // - // Clear any HBA interrupt status - // - AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar, EFI_AHCI_IS_OFFSET)); -} - -/** - Enable the FIS running for giving port. - - @param AhciBar AHCI bar address. - @param Port The number of port. - @param Timeout The timeout Value of enabling FIS. - - @retval EFI_DEVICE_ERROR The FIS enable setting fails. - @retval EFI_TIMEOUT The FIS enable setting is time out. - @retval EFI_SUCCESS The FIS enable successfully. - -**/ -EFI_STATUS -EFIAPI -AhciEnableFisReceive ( - IN UINT32 AhciBar, - IN UINT8 Port, - IN UINT64 Timeout - ) -{ - UINT32 Offset; - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE); - - return AhciWaitMmioSet ( - AhciBar, - Offset, - EFI_AHCI_PORT_CMD_FR, - EFI_AHCI_PORT_CMD_FR, - Timeout - ); -} - -/** - Disable the FIS running for giving port. - - @param AhciBar AHCI bar address. - @param Port The number of port. - @param Timeout The timeout Value of disabling FIS. - - @retval EFI_DEVICE_ERROR The FIS disable setting fails. - @retval EFI_TIMEOUT The FIS disable setting is time out. - @retval EFI_UNSUPPORTED The port is in running state. - @retval EFI_SUCCESS The FIS disable successfully. - -**/ -EFI_STATUS -EFIAPI -AhciDisableFisReceive ( - IN UINT32 AhciBar, - IN UINT8 Port, - IN UINT64 Timeout - ) -{ - UINT32 Offset; - UINT32 Data; - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - Data = AhciReadReg (AhciBar, Offset); - - // - // Before disabling Fis receive, the DMA engine of the port should NOT be in running status. - // - if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) { - return EFI_UNSUPPORTED; - } - - // - // Check if the Fis receive DMA engine for the port is running. - // - if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) { - return EFI_SUCCESS; - } - - AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE)); - - return AhciWaitMmioSet ( - AhciBar, - Offset, - EFI_AHCI_PORT_CMD_FR, - 0, - Timeout - ); -} - -/** - Build the command list, command table and prepare the fis receiver. - - @param AhciContext The pointer to the AHCI_CONTEXT. - @param Port The number of port. - @param PortMultiplier The timeout Value of stop. - @param CommandFis The control fis will be used for the transfer. - @param CommandList The command list will be used for the transfer. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The Length of the atapi command. - @param CommandSlotNumber The command slot will be used for the transfer. - @param DataPhysicalAddr The pointer to the Data Buffer pci bus master address. - @param DataLength The Data count to be transferred. - -**/ -VOID -EFIAPI -AhciBuildCommand ( - IN AHCI_CONTEXT *AhciContext, - IN UINT8 Port, - IN UINT8 PortMultiplier, - IN EFI_AHCI_COMMAND_FIS *CommandFis, - IN EFI_AHCI_COMMAND_LIST *CommandList, - IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, - IN UINT8 AtapiCommandLength, - IN UINT8 CommandSlotNumber, - IN OUT VOID *DataPhysicalAddr, - IN UINT64 DataLength - ) -{ - EFI_AHCI_REGISTERS *AhciRegisters; - UINT32 AhciBar; - UINT64 BaseAddr; - UINT64 PrdtNumber; - UINTN RemainedData; - UINTN MemAddr; - DATA_64 Data64; - UINT32 Offset; - - AhciRegisters = &AhciContext->AhciRegisters; - AhciBar = AhciContext->AhciBar; - - // - // Filling the PRDT - // - PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT); - - // - // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block. - // It also limits that the maximum amount of the PRDT entry in the command table - // is 65535. - // - ASSERT (PrdtNumber <= 1); - - Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis); - - BaseAddr = Data64.Uint64; - - ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS)); - - ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE)); - - CommandFis->AhciCFisPmNum = PortMultiplier; - - CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS)); - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - if (AtapiCommand != NULL) { - CopyMem ( - &AhciRegisters->AhciCommandTable->AtapiCmd, - AtapiCommand, - AtapiCommandLength - ); - - CommandList->AhciCmdA = 1; - CommandList->AhciCmdP = 1; - - AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI)); - } else { - AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI)); - } - - RemainedData = (UINTN) DataLength; - MemAddr = (UINTN) DataPhysicalAddr; - CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber; - - AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1; - - Data64.Uint64 = (UINT64)MemAddr; - AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba = Data64.Uint32.Lower32; - AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32; - - // - // Set the last PRDT to Interrupt On Complete - // - AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1; - - CopyMem ( - (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)), - CommandList, - sizeof (EFI_AHCI_COMMAND_LIST) - ); - - Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable; - AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32; - AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32; - AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier; - -} - -/** - Buid a command FIS. - - @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS Data structure. - @param AtaCommandBlock A pointer to the AhciBuildCommandFis Data structure. - -**/ -VOID -EFIAPI -AhciBuildCommandFis ( - IN OUT EFI_AHCI_COMMAND_FIS *CmdFis, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock - ) -{ - ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS)); - - CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D; - // - // Indicator it's a command - // - CmdFis->AhciCFisCmdInd = 0x1; - CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand; - - CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures; - CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp; - - CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber; - CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp; - - CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow; - CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp; - - CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh; - CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp; - - CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount; - CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp; - - CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0); -} - -/** - Start a PIO Data transfer on specific port. - - @param AhciContext The pointer to the AHCI_CONTEXT. - @param Port The number of port. - @param PortMultiplier The timeout Value of stop. - @param AtapiCommand The atapi command will be used for the transfer. - @param AtapiCommandLength The Length of the atapi command. - @param Read The transfer direction. - @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data. - @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data. - @param MemoryAddr The pointer to the Data Buffer. - @param DataCount The Data count to be transferred. - @param Timeout The timeout Value of non Data transfer. - - @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_UNSUPPORTED The device is not ready for transfer. - @retval EFI_SUCCESS The PIO Data transfer executes successfully. - -**/ -EFI_STATUS -EFIAPI -AhciPioTransfer ( - IN AHCI_CONTEXT *AhciContext, - IN UINT8 Port, - IN UINT8 PortMultiplier, - IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL, - IN UINT8 AtapiCommandLength, - IN BOOLEAN Read, - IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, - IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, - IN OUT VOID *MemoryAddr, - IN UINT32 DataCount, - IN UINT64 Timeout - ) -{ - EFI_STATUS Status; - EFI_AHCI_REGISTERS *AhciRegisters; - UINT32 AhciBar; - UINT32 FisBaseAddr; - UINT32 Offset; - UINT32 Delay; - EFI_AHCI_COMMAND_FIS CFis; - EFI_AHCI_COMMAND_LIST CmdList; - UINT32 PortTfd; - UINT32 PrdCount; - UINT32 OldRfisLo; - UINT32 OldRfisHi; - UINT32 OldCmdListLo; - UINT32 OldCmdListHi; - - AhciRegisters = &AhciContext->AhciRegisters; - AhciBar = AhciContext->AhciBar; - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB; - OldRfisLo = AhciReadReg (AhciBar, Offset); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU; - OldRfisHi = AhciReadReg (AhciBar, Offset); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB; - AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU; - AhciWriteReg (AhciBar, Offset, 0); - - // - // Single task envrionment, we only use one command table for all port - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB; - OldCmdListLo = AhciReadReg (AhciBar, Offset); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU; - OldCmdListHi = AhciReadReg (AhciBar, Offset); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB; - AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU; - AhciWriteReg (AhciBar, Offset, 0); - - // - // Package read needed - // - AhciBuildCommandFis (&CFis, AtaCommandBlock); - - ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST)); - - CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4; - CmdList.AhciCmdW = Read ? 0 : 1; - - AhciBuildCommand ( - AhciContext, - Port, - PortMultiplier, - &CFis, - &CmdList, - AtapiCommand, - AtapiCommandLength, - 0, - MemoryAddr, - DataCount - ); - - Status = AhciStartCommand ( - AhciBar, - Port, - 0, - Timeout - ); - if (EFI_ERROR (Status)) { - goto Exit; - } - - // - // Checking the status and wait the driver sending Data - // - FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis; - if (Read && (AtapiCommand == 0)) { - // - // Wait device sends the PIO setup fis before Data transfer - // - Status = EFI_TIMEOUT; - Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1); - do { - Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET; - - Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0); - if (!EFI_ERROR (Status)) { - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD; - PortTfd = AhciReadReg (AhciBar, (UINT32) Offset); - // - // PxTFD will be updated if there is a D2H or SetupFIS received. - // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS. - // - if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) { - Status = EFI_DEVICE_ERROR; - break; - } - - PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc)); - if (PrdCount == DataCount) { - break; - } - } - - Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET; - Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0); - if (!EFI_ERROR (Status)) { - Status = EFI_DEVICE_ERROR; - break; - } - - // - // Stall for 100 microseconds. - // - MicroSecondDelay(100); - - Delay--; - } while (Delay > 0); - } else { - // - // Wait for D2H Fis is received - // - Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET; - Status = AhciWaitMemSet ( - Offset, - EFI_AHCI_FIS_TYPE_MASK, - EFI_AHCI_FIS_REGISTER_D2H, - Timeout - ); - - if (EFI_ERROR (Status)) { - goto Exit; - } - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD; - PortTfd = AhciReadReg (AhciBar, (UINT32) Offset); - if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) { - Status = EFI_DEVICE_ERROR; - } - } - -Exit: - AhciStopCommand ( - AhciBar, - Port, - Timeout - ); - - AhciDisableFisReceive ( - AhciBar, - Port, - Timeout - ); - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB; - AhciWriteReg (AhciBar, Offset, OldRfisLo); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU; - AhciWriteReg (AhciBar, Offset, OldRfisHi); - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB; - AhciWriteReg (AhciBar, Offset, OldCmdListLo); - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU; - AhciWriteReg (AhciBar, Offset, OldCmdListHi); - - return Status; -} - -/** - Stop command running for giving port - - @param AhciBar AHCI bar address. - @param Port The number of port. - @param Timeout The timeout Value of stop. - - @retval EFI_DEVICE_ERROR The command stop unsuccessfully. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_SUCCESS The command stop successfully. - -**/ -EFI_STATUS -EFIAPI -AhciStopCommand ( - IN UINT32 AhciBar, - IN UINT8 Port, - IN UINT64 Timeout - ) -{ - UINT32 Offset; - UINT32 Data; - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - Data = AhciReadReg (AhciBar, Offset); - - if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) { - return EFI_SUCCESS; - } - - if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) { - AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST)); - } - - return AhciWaitMmioSet ( - AhciBar, - Offset, - EFI_AHCI_PORT_CMD_CR, - 0, - Timeout - ); -} - -/** - Start command for give slot on specific port. - - @param AhciBar AHCI bar address. - @param Port The number of port. - @param CommandSlot The number of CommandSlot. - @param Timeout The timeout Value of start. - - @retval EFI_DEVICE_ERROR The command start unsuccessfully. - @retval EFI_TIMEOUT The operation is time out. - @retval EFI_SUCCESS The command start successfully. - -**/ -EFI_STATUS -EFIAPI -AhciStartCommand ( - IN UINT32 AhciBar, - IN UINT8 Port, - IN UINT8 CommandSlot, - IN UINT64 Timeout - ) -{ - UINT32 CmdSlotBit; - EFI_STATUS Status; - UINT32 PortStatus; - UINT32 StartCmd; - UINT32 PortTfd; - UINT32 Offset; - UINT32 Capability; - - // - // Collect AHCI controller information - // - Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET); - - CmdSlotBit = (UINT32) (1 << CommandSlot); - - AhciClearPortStatus ( - AhciBar, - Port - ); - - Status = AhciEnableFisReceive ( - AhciBar, - Port, - Timeout - ); - - if (EFI_ERROR (Status)) { - return Status; - } - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - PortStatus = AhciReadReg (AhciBar, Offset); - - StartCmd = 0; - if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) { - StartCmd = AhciReadReg (AhciBar, Offset); - StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK; - StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE; - } - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD; - PortTfd = AhciReadReg (AhciBar, Offset); - - if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) { - if ((Capability & BIT24) != 0) { - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL); - - AhciWaitMmioSet ( - AhciBar, - Offset, - EFI_AHCI_PORT_CMD_COL, - 0, - Timeout - ); - } - } - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd); - - // - // Setting the command - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT; - AhciAndReg (AhciBar, Offset, 0); - AhciOrReg (AhciBar, Offset, CmdSlotBit); - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI; - AhciAndReg (AhciBar, Offset, 0); - AhciOrReg (AhciBar, Offset, CmdSlotBit); - return EFI_SUCCESS; -} - - -/** - Do AHCI HBA reset. - - @param[in] AhciBar AHCI bar address. - @param[in] Timeout The timeout Value of reset. - - @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset. - @retval EFI_TIMEOUT The reset operation is time out. - @retval EFI_SUCCESS AHCI controller is reset successfully. - -**/ -EFI_STATUS -EFIAPI -AhciReset ( - IN UINT32 AhciBar, - IN UINT64 Timeout - ) -{ - UINT32 Delay; - UINT32 Value; - UINT32 Capability; - - // - // Collect AHCI controller information - // - Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET); - - // - // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set - // - if ((Capability & EFI_AHCI_CAP_SAM) == 0) { - AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE); - } - - AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET); - - Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1); - - do { - Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET); - if ((Value & EFI_AHCI_GHC_RESET) == 0) { - return EFI_SUCCESS; - } - - // - // Stall for 100 microseconds. - // - MicroSecondDelay(100); - - Delay--; - } while (Delay > 0); - - return EFI_TIMEOUT; - - -} - -/** - Allocate transfer-related data struct which is used at AHCI mode. - - @param[in, out] AhciContext The pointer to the AHCI_CONTEXT. - - @retval EFI_OUT_OF_RESOURCE No enough resource. - @retval EFI_SUCCESS Successful to allocate resource. - -**/ -EFI_STATUS -EFIAPI -AhciAllocateResource ( - IN OUT AHCI_CONTEXT *AhciContext - ) -{ - EFI_STATUS Status; - EFI_AHCI_REGISTERS *AhciRegisters; - EFI_PHYSICAL_ADDRESS DeviceAddress; - VOID *Base; - VOID *Mapping; - - AhciRegisters = &AhciContext->AhciRegisters; - - // - // Allocate resources required by AHCI host controller. - // - Status = IoMmuAllocateBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), - &Base, - &DeviceAddress, - &Mapping - ); - if (EFI_ERROR (Status)) { - return EFI_OUT_OF_RESOURCES; - } - ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); - AhciRegisters->AhciRFisMapping = Mapping; - AhciRegisters->AhciRFis = Base; - ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS))); - - Status = IoMmuAllocateBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)), - &Base, - &DeviceAddress, - &Mapping - ); - if (EFI_ERROR (Status)) { - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), - AhciRegisters->AhciRFis, - AhciRegisters->AhciRFisMapping - ); - AhciRegisters->AhciRFis = NULL; - return EFI_OUT_OF_RESOURCES; - } - ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); - AhciRegisters->AhciCmdListMapping = Mapping; - AhciRegisters->AhciCmdList = Base; - ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST))); - - Status = IoMmuAllocateBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)), - &Base, - &DeviceAddress, - &Mapping - ); - if (EFI_ERROR (Status)) { - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)), - AhciRegisters->AhciCmdList, - AhciRegisters->AhciCmdListMapping - ); - AhciRegisters->AhciCmdList = NULL; - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), - AhciRegisters->AhciRFis, - AhciRegisters->AhciRFisMapping - ); - AhciRegisters->AhciRFis = NULL; - return EFI_OUT_OF_RESOURCES; - } - ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); - AhciRegisters->AhciCommandTableMapping = Mapping; - AhciRegisters->AhciCommandTable = Base; - ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE))); - - // - // Allocate resources for data transfer. - // - Status = IoMmuAllocateBuffer ( - EFI_SIZE_TO_PAGES (HDD_PAYLOAD), - &Base, - &DeviceAddress, - &Mapping - ); - if (EFI_ERROR (Status)) { - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), - AhciRegisters->AhciCommandTable, - AhciRegisters->AhciCommandTableMapping - ); - AhciRegisters->AhciCommandTable = NULL; - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)), - AhciRegisters->AhciCmdList, - AhciRegisters->AhciCmdListMapping - ); - AhciRegisters->AhciCmdList = NULL; - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), - AhciRegisters->AhciRFis, - AhciRegisters->AhciRFisMapping - ); - AhciRegisters->AhciRFis = NULL; - return EFI_OUT_OF_RESOURCES; - } - ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base)); - AhciContext->BufferMapping = Mapping; - AhciContext->Buffer = Base; - ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (HDD_PAYLOAD)); - - DEBUG (( - DEBUG_INFO, - "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n", - __FUNCTION__, - AhciContext->Buffer, - AhciRegisters->AhciRFis, - AhciRegisters->AhciCmdList, - AhciRegisters->AhciCommandTable - )); - return EFI_SUCCESS; -} - -/** - Free allocated transfer-related data struct which is used at AHCI mode. - - @param[in, out] AhciContext The pointer to the AHCI_CONTEXT. - -**/ -VOID -EFIAPI -AhciFreeResource ( - IN OUT AHCI_CONTEXT *AhciContext - ) -{ - EFI_AHCI_REGISTERS *AhciRegisters; - - AhciRegisters = &AhciContext->AhciRegisters; - - if (AhciContext->Buffer != NULL) { - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (HDD_PAYLOAD), - AhciContext->Buffer, - AhciContext->BufferMapping - ); - AhciContext->Buffer = NULL; - } - - if (AhciRegisters->AhciCommandTable != NULL) { - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)), - AhciRegisters->AhciCommandTable, - AhciRegisters->AhciCommandTableMapping - ); - AhciRegisters->AhciCommandTable = NULL; - } - - if (AhciRegisters->AhciCmdList != NULL) { - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)), - AhciRegisters->AhciCmdList, - AhciRegisters->AhciCmdListMapping - ); - AhciRegisters->AhciCmdList = NULL; - } - - if (AhciRegisters->AhciRFis != NULL) { - IoMmuFreeBuffer ( - EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)), - AhciRegisters->AhciRFis, - AhciRegisters->AhciRFisMapping - ); - AhciRegisters->AhciRFis = NULL; - } -} - -/** - Initialize ATA host controller at AHCI mode. - - The function is designed to initialize ATA host controller. - - @param[in] AhciContext The pointer to the AHCI_CONTEXT. - @param[in] Port The port number to do initialization. - -**/ -EFI_STATUS -EFIAPI -AhciModeInitialize ( - IN AHCI_CONTEXT *AhciContext, - IN UINT8 Port - ) -{ - EFI_STATUS Status; - EFI_AHCI_REGISTERS *AhciRegisters; - UINT32 AhciBar; - UINT32 Capability; - UINT32 Offset; - UINT32 Data; - UINT32 PhyDetectDelay; - - AhciRegisters = &AhciContext->AhciRegisters; - AhciBar = AhciContext->AhciBar; - - Status = AhciReset (AhciBar, ATA_TIMEOUT); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Collect AHCI controller information - // - Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET); - - // - // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set - // - if ((Capability & EFI_AHCI_CAP_SAM) == 0) { - AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE); - } - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB; - AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis); - - // - // Single task envrionment, we only use one command table for all port - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB; - AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList); - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD; - Data = AhciReadReg (AhciBar, Offset); - if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) { - AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD); - } - - if ((Capability & BIT27) != 0) { - AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD); - } - - // - // Disable aggressive power management. - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL; - AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT); - // - // Disable the reporting of the corresponding interrupt to system software. - // - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE; - AhciAndReg (AhciBar, Offset, 0); - - Status = AhciEnableFisReceive ( - AhciBar, - Port, - 5000000 - ); - ASSERT_EFI_ERROR (Status); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ - // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec. - // - PhyDetectDelay = 16 * 1000; - do { - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR; - if (AhciReadReg(AhciBar, Offset) != 0) { - AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset)); - } - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD; - - Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK; - if (Data == 0) { - break; - } - - MicroSecondDelay (1000); - PhyDetectDelay--; - } while (PhyDetectDelay > 0); - - if (PhyDetectDelay == 0) { - return EFI_NOT_FOUND; - } - - Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG; - Status = AhciWaitMmioSet ( - AhciBar, - Offset, - 0x0000FFFF, - 0x00000101, - 160000000 - ); - - if (EFI_ERROR (Status)) { - return Status; - } - - return Status; -} -