summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c118
-rw-r--r--MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c35
-rw-r--r--MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h30
-rw-r--r--MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf4
-rw-r--r--MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c516
-rw-r--r--MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h257
6 files changed, 960 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
index 11754b3057..7287f8290e 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciMode.c
@@ -1873,6 +1873,124 @@ AhciModeInitialization (
}
/**
+ Transfer data from ATA device.
+
+ This function performs one ATA pass through transaction to transfer data from/to
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
+ interface of ATA pass through.
+
+ @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsWrite Indicates whether it is a write operation.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TransferAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT VOID *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINT32 TransferLength,
+ IN BOOLEAN IsWrite
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ EDKII_PEI_ATA_PASS_THRU_PPI *AtaPassThru;
+ EFI_ATA_COMMAND_BLOCK Acb;
+ EFI_ATA_PASS_THRU_COMMAND_PACKET Packet;
+
+ Private = DeviceData->Private;
+ AtaPassThru = &Private->AtaPassThruPpi;
+
+ //
+ // Ensure Lba48Bit and IsWrite are valid boolean values
+ //
+ ASSERT ((UINTN) DeviceData->Lba48Bit < 2);
+ ASSERT ((UINTN) IsWrite < 2);
+ if (((UINTN) DeviceData->Lba48Bit >= 2) ||
+ ((UINTN) IsWrite >= 2)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Prepare for ATA command block.
+ //
+ ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK));
+ Acb.AtaCommand = mAtaCommands[DeviceData->Lba48Bit][IsWrite];
+ Acb.AtaSectorNumber = (UINT8) StartLba;
+ Acb.AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);
+ Acb.AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);
+ Acb.AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 |
+ (DeviceData->PortMultiplier == 0xFFFF ?
+ 0 : (DeviceData->PortMultiplier << 4)));
+ Acb.AtaSectorCount = (UINT8) TransferLength;
+ if (DeviceData->Lba48Bit) {
+ Acb.AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);
+ Acb.AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);
+ Acb.AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);
+ Acb.AtaSectorCountExp = (UINT8) (TransferLength >> 8);
+ } else {
+ Acb.AtaDeviceHead = (UINT8) (Acb.AtaDeviceHead | RShiftU64 (StartLba, 24));
+ }
+
+ //
+ // Prepare for ATA pass through packet.
+ //
+ ZeroMem (&Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));
+ if (IsWrite) {
+ Packet.OutDataBuffer = Buffer;
+ Packet.OutTransferLength = TransferLength;
+ } else {
+ Packet.InDataBuffer = Buffer;
+ Packet.InTransferLength = TransferLength;
+ }
+ Packet.Asb = NULL;
+ Packet.Acb = &Acb;
+ Packet.Protocol = mAtaPassThruCmdProtocols[IsWrite];
+ Packet.Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;
+ //
+ // |------------------------|-----------------|
+ // | ATA PIO Transfer Mode | Transfer Rate |
+ // |------------------------|-----------------|
+ // | PIO Mode 0 | 3.3Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 1 | 5.2Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 2 | 8.3Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 3 | 11.1Mbytes/sec |
+ // |------------------------|-----------------|
+ // | PIO Mode 4 | 16.6Mbytes/sec |
+ // |------------------------|-----------------|
+ //
+ // As AtaBus is used to manage ATA devices, we have to use the lowest transfer
+ // rate to calculate the possible maximum timeout value for each read/write
+ // operation. The timout value is rounded up to nearest integar and here an
+ // additional 30s is added to follow ATA spec in which it mentioned that the
+ // device may take up to 30s to respond commands in the Standby/Idle mode.
+ //
+ // Calculate the maximum timeout value for PIO read/write operation.
+ //
+ Packet.Timeout = TIMER_PERIOD_SECONDS (
+ DivU64x32 (
+ MultU64x32 (TransferLength, DeviceData->Media.BlockSize),
+ 3300000
+ ) + 31
+ );
+
+ return AtaPassThru->PassThru (
+ AtaPassThru,
+ DeviceData->Port,
+ DeviceData->PortMultiplier,
+ &Packet
+ );
+}
+
+/**
Trust transfer data from/to ATA device.
This function performs one ATA pass through transaction to do a trust transfer
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
index 29e0aa7d65..31b072c118 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
@@ -16,6 +16,18 @@ EFI_PEI_PPI_DESCRIPTOR mAhciAtaPassThruPpiListTemplate = {
NULL
};
+EFI_PEI_PPI_DESCRIPTOR mAhciBlkIoPpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mAhciBlkIo2PpiListTemplate = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ NULL
+};
+
EFI_PEI_PPI_DESCRIPTOR mAhciStorageSecurityPpiListTemplate = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEdkiiPeiStorageSecurityCommandPpiGuid,
@@ -265,6 +277,29 @@ AtaAhciPeimEntry (
Private->AtaPassThruPpiList.Ppi = &Private->AtaPassThruPpi;
PeiServicesInstallPpi (&Private->AtaPassThruPpiList);
+ Private->BlkIoPpi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo;
+ Private->BlkIoPpi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo;
+ Private->BlkIoPpi.ReadBlocks = AhciBlockIoReadBlocks;
+ CopyMem (
+ &Private->BlkIoPpiList,
+ &mAhciBlkIoPpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->BlkIoPpiList.Ppi = &Private->BlkIoPpi;
+ PeiServicesInstallPpi (&Private->BlkIoPpiList);
+
+ Private->BlkIo2Ppi.Revision = EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION;
+ Private->BlkIo2Ppi.GetNumberOfBlockDevices = AhciBlockIoGetDeviceNo2;
+ Private->BlkIo2Ppi.GetBlockDeviceMediaInfo = AhciBlockIoGetMediaInfo2;
+ Private->BlkIo2Ppi.ReadBlocks = AhciBlockIoReadBlocks2;
+ CopyMem (
+ &Private->BlkIo2PpiList,
+ &mAhciBlkIo2PpiListTemplate,
+ sizeof (EFI_PEI_PPI_DESCRIPTOR)
+ );
+ Private->BlkIo2PpiList.Ppi = &Private->BlkIo2Ppi;
+ PeiServicesInstallPpi (&Private->BlkIo2PpiList);
+
if (Private->TrustComputingDevices != 0) {
DEBUG ((
DEBUG_INFO,
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
index e6a9c0a333..9a34dc6e4f 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.h
@@ -19,6 +19,7 @@
#include <Ppi/IoMmu.h>
#include <Ppi/EndOfPeiPhase.h>
#include <Ppi/AtaPassThru.h>
+#include <Ppi/BlockIo.h>
#include <Ppi/BlockIo2.h>
#include <Ppi/StorageSecurityCommand.h>
@@ -35,6 +36,7 @@
typedef struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA PEI_AHCI_CONTROLLER_PRIVATE_DATA;
#include "AhciPeiPassThru.h"
+#include "AhciPeiBlockIo.h"
#include "AhciPeiStorageSecurity.h"
//
@@ -312,6 +314,8 @@ struct _PEI_AHCI_CONTROLLER_PRIVATE_DATA {
EFI_ATA_PASS_THRU_MODE AtaPassThruMode;
EDKII_PEI_ATA_PASS_THRU_PPI AtaPassThruPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI BlkIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI BlkIo2Ppi;
EDKII_PEI_STORAGE_SECURITY_CMD_PPI StorageSecurityPpi;
EFI_PEI_PPI_DESCRIPTOR AtaPassThruPpiList;
EFI_PEI_PPI_DESCRIPTOR BlkIoPpiList;
@@ -554,6 +558,32 @@ AhciModeInitialization (
);
/**
+ Transfer data from ATA device.
+
+ This function performs one ATA pass through transaction to transfer data from/to
+ ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru
+ interface of ATA pass through.
+
+ @param[in] DeviceData A pointer to PEI_AHCI_ATA_DEVICE_DATA structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] TransferLength The block number or sector count of the transfer.
+ @param[in] IsWrite Indicates whether it is a write operation.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+TransferAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT VOID *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINT32 TransferLength,
+ IN BOOLEAN IsWrite
+ );
+
+/**
Trust transfer data from/to ATA device.
This function performs one ATA pass through transaction to do a trust transfer
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
index bf686a198f..912ff7a8ba 100644
--- a/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPei.inf
@@ -26,6 +26,8 @@
[Sources]
AhciPei.c
AhciPei.h
+ AhciPeiBlockIo.c
+ AhciPeiBlockIo.h
AhciPeiPassThru.c
AhciPeiPassThru.h
AhciPeiS3.c
@@ -54,6 +56,8 @@
gEdkiiIoMmuPpiGuid ## CONSUMES
gEfiEndOfPeiSignalPpiGuid ## CONSUMES
gEdkiiPeiAtaPassThruPpiGuid ## SOMETIMES_PRODUCES
+ gEfiPeiVirtualBlockIoPpiGuid ## SOMETIMES_PRODUCES
+ gEfiPeiVirtualBlockIo2PpiGuid ## SOMETIMES_PRODUCES
gEdkiiPeiStorageSecurityCommandPpiGuid ## SOMETIMES_PRODUCES
[Guids]
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
new file mode 100644
index 0000000000..e7c7a39539
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.c
@@ -0,0 +1,516 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "AhciPei.h"
+
+/**
+ Traverse the attached ATA devices list to find out the device with given index.
+
+ @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA
+ instance.
+ @param[in] DeviceIndex The device index.
+
+ @retval The pointer to the PEI_AHCI_ATA_DEVICE_DATA structure of the device
+ info to access.
+
+**/
+PEI_AHCI_ATA_DEVICE_DATA *
+SearchDeviceByIndex (
+ IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private,
+ IN UINTN DeviceIndex
+ )
+{
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+ LIST_ENTRY *Node;
+
+ if ((DeviceIndex == 0) || (DeviceIndex > Private->ActiveDevices)) {
+ return NULL;
+ }
+
+ Node = GetFirstNode (&Private->DeviceList);
+ while (!IsNull (&Private->DeviceList, Node)) {
+ DeviceData = AHCI_PEI_ATA_DEVICE_INFO_FROM_THIS (Node);
+
+ if (DeviceData->DeviceIndex == DeviceIndex) {
+ return DeviceData;
+ }
+
+ Node = GetNextNode (&Private->DeviceList, Node);
+ }
+
+ return NULL;
+}
+
+/**
+ Read a number of blocks from ATA device.
+
+ This function performs ATA pass through transactions to read data from ATA device.
+ It may separate the read request into several ATA pass through transactions.
+
+ @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA
+ data structure.
+ @param[in,out] Buffer The pointer to the current transaction buffer.
+ @param[in] StartLba The starting logical block address to be accessed.
+ @param[in] NumberOfBlocks The block number or sector count of the transfer.
+
+ @retval EFI_SUCCESS The data transfer is complete successfully.
+ @return Others Some error occurs when transferring data.
+
+**/
+EFI_STATUS
+AccessAtaDevice (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ IN OUT UINT8 *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ UINTN MaxTransferBlockNumber;
+ UINTN TransferBlockNumber;
+ UINTN BlockSize;
+
+ //
+ // Ensure Lba48Bit is a valid boolean value
+ //
+ ASSERT ((UINTN) DeviceData->Lba48Bit < 2);
+ if ((UINTN) DeviceData->Lba48Bit >= 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ MaxTransferBlockNumber = mMaxTransferBlockNumber[DeviceData->Lba48Bit];
+ BlockSize = DeviceData->Media.BlockSize;
+
+ do {
+ if (NumberOfBlocks > MaxTransferBlockNumber) {
+ TransferBlockNumber = MaxTransferBlockNumber;
+ NumberOfBlocks -= MaxTransferBlockNumber;
+ } else {
+ TransferBlockNumber = NumberOfBlocks;
+ NumberOfBlocks = 0;
+ }
+ DEBUG ((
+ DEBUG_BLKIO, "%a: Blocking AccessAtaDevice, TransferBlockNumber = %x; StartLba = %x\n",
+ __FUNCTION__, TransferBlockNumber, StartLba
+ ));
+
+ Status = TransferAtaDevice (
+ DeviceData,
+ Buffer,
+ StartLba,
+ (UINT32) TransferBlockNumber,
+ FALSE // Read
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ StartLba += TransferBlockNumber;
+ Buffer += TransferBlockNumber * BlockSize;
+ } while (NumberOfBlocks > 0);
+
+ return Status;
+}
+
+/**
+ Read specified bytes from Lba from the device.
+
+ @param[in] DeviceData The pointer to the PEI_AHCI_ATA_DEVICE_DATA data structure.
+ @param[out] Buffer The Buffer used to store the Data read from the device.
+ @param[in] StartLba The start block number.
+ @param[in] BufferSize Total bytes to be read.
+
+ @retval EFI_SUCCESS Data are read from the device.
+ @retval Others Fail to read all the data.
+
+**/
+EFI_STATUS
+AhciRead (
+ IN PEI_AHCI_ATA_DEVICE_DATA *DeviceData,
+ OUT VOID *Buffer,
+ IN EFI_LBA StartLba,
+ IN UINTN BufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+
+ //
+ // Check parameters.
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BlockSize = DeviceData->Media.BlockSize;
+ if ((BufferSize % BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (StartLba > DeviceData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+ NumberOfBlocks = BufferSize / BlockSize;
+ if (NumberOfBlocks - 1 > DeviceData->Media.LastBlock - StartLba) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Invoke low level AtaDevice Access Routine.
+ //
+ Status = AccessAtaDevice (DeviceData, Buffer, StartLba, NumberOfBlocks);
+
+ return Status;
+}
+
+
+/**
+ Gets the count of block I/O devices that one specific block driver detects.
+
+ This function is used for getting the count of block I/O devices that one
+ specific block driver detects. If no device is detected, then the function
+ will return zero.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberBlockDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+ *NumberBlockDevices = Private->ActiveDevices;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets a block device's media information.
+
+ This function will provide the caller with the specified block device's media
+ information. If the media changes, calling this function will update the media
+ information accordingly.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, the PPIs that
+ want to talk to a single device must specify the
+ device index that was assigned during the enumeration
+ process. This index is a number from one to
+ NumberBlockDevices.
+ @param[out] MediaInfo The media information of the specified block media.
+ The caller is responsible for the ownership of this
+ data structure.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @retval EFI_SUCCESS Media information about the specified block device
+ was obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ MediaInfo->DeviceType = (EFI_PEI_BLOCK_DEVICE_TYPE) EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK;
+ MediaInfo->MediaPresent = TRUE;
+ MediaInfo->LastBlock = (UINTN) DeviceData->Media.LastBlock;
+ MediaInfo->BlockSize = DeviceData->Media.BlockSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads the requested number of blocks from the specified block device.
+
+ The function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned. If there is no media in the device,
+ the function returns EFI_NO_MEDIA.
+
+ @param[in] PeiServices General-purpose services that are available to
+ every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, PPIs that
+ want to talk to a single device must specify the device
+ index that was assigned during the enumeration process.
+ This index is a number from one to NumberBlockDevices.
+ @param[in] StartLBA The starting logical block address (LBA) to read from
+ on the device
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be
+ a multiple of the intrinsic block size of the device.
+ @param[out] Buffer A pointer to the destination buffer for the data.
+ The caller is responsible for the ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the read operation.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not properly aligned.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoReadBlocks (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO (This);
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return AhciRead (DeviceData, Buffer, StartLBA, BufferSize);
+}
+
+/**
+ Gets the count of block I/O devices that one specific block driver detects.
+
+ This function is used for getting the count of block I/O devices that one
+ specific block driver detects. If no device is detected, then the function
+ will return zero.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL || NumberBlockDevices == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ *NumberBlockDevices = Private->ActiveDevices;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets a block device's media information.
+
+ This function will provide the caller with the specified block device's media
+ information. If the media changes, calling this function will update the media
+ information accordingly.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, the PPIs that
+ want to talk to a single device must specify the
+ device index that was assigned during the enumeration
+ process. This index is a number from one to
+ NumberBlockDevices.
+ @param[out] MediaInfo The media information of the specified block media.
+ The caller is responsible for the ownership of this
+ data structure.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @retval EFI_SUCCESS Media information about the specified block device
+ was obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+ PEI_AHCI_ATA_DEVICE_DATA *DeviceData;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ DeviceData = SearchDeviceByIndex (Private, DeviceIndex);
+ if (DeviceData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ CopyMem (
+ MediaInfo,
+ &DeviceData->Media,
+ sizeof (EFI_PEI_BLOCK_IO2_MEDIA)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads the requested number of blocks from the specified block device.
+
+ The function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned. If there is no media in the device,
+ the function returns EFI_NO_MEDIA.
+
+ @param[in] PeiServices General-purpose services that are available to
+ every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, PPIs that
+ want to talk to a single device must specify the device
+ index that was assigned during the enumeration process.
+ This index is a number from one to NumberBlockDevices.
+ @param[in] StartLBA The starting logical block address (LBA) to read from
+ on the device
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be
+ a multiple of the intrinsic block size of the device.
+ @param[out] Buffer A pointer to the destination buffer for the data.
+ The caller is responsible for the ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the read operation.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not properly aligned.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_BLKIO2 (This);
+ return AhciBlockIoReadBlocks (
+ PeiServices,
+ &Private->BlkIoPpi,
+ DeviceIndex,
+ StartLBA,
+ BufferSize,
+ Buffer
+ );
+}
diff --git a/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h
new file mode 100644
index 0000000000..5896ae5acf
--- /dev/null
+++ b/MdeModulePkg/Bus/Ata/AhciPei/AhciPeiBlockIo.h
@@ -0,0 +1,257 @@
+/** @file
+ The AhciPei driver is used to manage ATA hard disk device working under AHCI
+ mode at PEI phase.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _AHCI_PEI_BLOCKIO_H_
+#define _AHCI_PEI_BLOCKIO_H_
+
+//
+// ATA hard disk device for EFI_PEI_BLOCK_DEVICE_TYPE
+//
+#define EDKII_PEI_BLOCK_DEVICE_TYPE_ATA_HARD_DISK 8
+
+/**
+ Gets the count of block I/O devices that one specific block driver detects.
+
+ This function is used for getting the count of block I/O devices that one
+ specific block driver detects. If no device is detected, then the function
+ will return zero.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ Gets a block device's media information.
+
+ This function will provide the caller with the specified block device's media
+ information. If the media changes, calling this function will update the media
+ information accordingly.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, the PPIs that
+ want to talk to a single device must specify the
+ device index that was assigned during the enumeration
+ process. This index is a number from one to
+ NumberBlockDevices.
+ @param[out] MediaInfo The media information of the specified block media.
+ The caller is responsible for the ownership of this
+ data structure.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @retval EFI_SUCCESS Media information about the specified block device
+ was obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ Reads the requested number of blocks from the specified block device.
+
+ The function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned. If there is no media in the device,
+ the function returns EFI_NO_MEDIA.
+
+ @param[in] PeiServices General-purpose services that are available to
+ every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, PPIs that
+ want to talk to a single device must specify the device
+ index that was assigned during the enumeration process.
+ This index is a number from one to NumberBlockDevices.
+ @param[in] StartLBA The starting logical block address (LBA) to read from
+ on the device
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be
+ a multiple of the intrinsic block size of the device.
+ @param[out] Buffer A pointer to the destination buffer for the data.
+ The caller is responsible for the ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the read operation.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not properly aligned.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoReadBlocks (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Gets the count of block I/O devices that one specific block driver detects.
+
+ This function is used for getting the count of block I/O devices that one
+ specific block driver detects. If no device is detected, then the function
+ will return zero.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS The operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetDeviceNo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ Gets a block device's media information.
+
+ This function will provide the caller with the specified block device's media
+ information. If the media changes, calling this function will update the media
+ information accordingly.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, the PPIs that
+ want to talk to a single device must specify the
+ device index that was assigned during the enumeration
+ process. This index is a number from one to
+ NumberBlockDevices.
+ @param[out] MediaInfo The media information of the specified block media.
+ The caller is responsible for the ownership of this
+ data structure.
+
+ @par Note:
+ The MediaInfo structure describes an enumeration of possible block device
+ types. This enumeration exists because no device paths are actually passed
+ across interfaces that describe the type or class of hardware that is publishing
+ the block I/O interface. This enumeration will allow for policy decisions
+ in the Recovery PEIM, such as "Try to recover from legacy floppy first,
+ LS-120 second, CD-ROM third." If there are multiple partitions abstracted
+ by a given device type, they should be reported in ascending order; this
+ order also applies to nested partitions, such as legacy MBR, where the
+ outermost partitions would have precedence in the reporting order. The
+ same logic applies to systems such as IDE that have precedence relationships
+ like "Master/Slave" or "Primary/Secondary". The master device should be
+ reported first, the slave second.
+
+ @retval EFI_SUCCESS Media information about the specified block device
+ was obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
+ error.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoGetMediaInfo2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO2_MEDIA *MediaInfo
+ );
+
+/**
+ Reads the requested number of blocks from the specified block device.
+
+ The function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned. If there is no media in the device,
+ the function returns EFI_NO_MEDIA.
+
+ @param[in] PeiServices General-purpose services that are available to
+ every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, PPIs that
+ want to talk to a single device must specify the device
+ index that was assigned during the enumeration process.
+ This index is a number from one to NumberBlockDevices.
+ @param[in] StartLBA The starting logical block address (LBA) to read from
+ on the device
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be
+ a multiple of the intrinsic block size of the device.
+ @param[out] Buffer A pointer to the destination buffer for the data.
+ The caller is responsible for the ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the read operation.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not properly aligned.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciBlockIoReadBlocks2 (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+#endif