mirror of https://github.com/acidanthera/audk.git
339 lines
11 KiB
C
339 lines
11 KiB
C
/** @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"
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR mAhciAtaPassThruPpiListTemplate = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEdkiiPeiAtaPassThruPpiGuid,
|
|
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,
|
|
NULL
|
|
};
|
|
|
|
EFI_PEI_NOTIFY_DESCRIPTOR mAhciEndOfPeiNotifyListTemplate = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiEndOfPeiSignalPpiGuid,
|
|
AhciPeimEndOfPei
|
|
};
|
|
|
|
|
|
/**
|
|
Free the DMA resources allocated by an ATA AHCI controller.
|
|
|
|
@param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA data
|
|
structure.
|
|
|
|
**/
|
|
VOID
|
|
AhciFreeDmaResource (
|
|
IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private
|
|
)
|
|
{
|
|
EFI_AHCI_REGISTERS *AhciRegisters;
|
|
|
|
ASSERT (Private != NULL);
|
|
|
|
AhciRegisters = &Private->AhciRegisters;
|
|
|
|
if (AhciRegisters->AhciRFisMap != NULL) {
|
|
IoMmuFreeBuffer (
|
|
EFI_SIZE_TO_PAGES (AhciRegisters->MaxRFisSize),
|
|
AhciRegisters->AhciRFis,
|
|
AhciRegisters->AhciRFisMap
|
|
);
|
|
}
|
|
|
|
if (AhciRegisters->AhciCmdListMap != NULL) {
|
|
IoMmuFreeBuffer (
|
|
EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdListSize),
|
|
AhciRegisters->AhciCmdList,
|
|
AhciRegisters->AhciCmdListMap
|
|
);
|
|
}
|
|
|
|
if (AhciRegisters->AhciCmdTableMap != NULL) {
|
|
IoMmuFreeBuffer (
|
|
EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdTableSize),
|
|
AhciRegisters->AhciCmdTable,
|
|
AhciRegisters->AhciCmdTableMap
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
One notified function to cleanup the allocated DMA buffers at EndOfPei.
|
|
|
|
@param[in] PeiServices Pointer to PEI Services Table.
|
|
@param[in] NotifyDescriptor Pointer to the descriptor for the Notification
|
|
event that caused this function to execute.
|
|
@param[in] Ppi Pointer to the PPI data associated with this function.
|
|
|
|
@retval EFI_SUCCESS The function completes successfully
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AhciPeimEndOfPei (
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
|
IN VOID *Ppi
|
|
)
|
|
{
|
|
PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
|
|
|
|
Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);
|
|
AhciFreeDmaResource (Private);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Entry point of the PEIM.
|
|
|
|
@param[in] FileHandle Handle of the file being invoked.
|
|
@param[in] PeiServices Describes the list of possible PEI Services.
|
|
|
|
@retval EFI_SUCCESS PPI successfully installed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AtaAhciPeimEntry (
|
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_BOOT_MODE BootMode;
|
|
EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *AhciHcPpi;
|
|
UINT8 Controller;
|
|
UINTN MmioBase;
|
|
UINTN DevicePathLength;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UINT32 PortBitMap;
|
|
PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;
|
|
UINT8 NumberOfPorts;
|
|
|
|
DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));
|
|
|
|
//
|
|
// Get the current boot mode.
|
|
//
|
|
Status = PeiServicesGetBootMode (&BootMode);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Locate the ATA AHCI host controller PPI.
|
|
//
|
|
Status = PeiServicesLocatePpi (
|
|
&gEdkiiPeiAtaAhciHostControllerPpiGuid,
|
|
0,
|
|
NULL,
|
|
(VOID **) &AhciHcPpi
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Failed to locate AtaAhciHostControllerPpi.\n", __FUNCTION__));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Controller = 0;
|
|
MmioBase = 0;
|
|
while (TRUE) {
|
|
Status = AhciHcPpi->GetAhciHcMmioBar (
|
|
AhciHcPpi,
|
|
Controller,
|
|
&MmioBase
|
|
);
|
|
//
|
|
// When status is error, meant no controller is found.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
Status = AhciHcPpi->GetAhciHcDevicePath (
|
|
AhciHcPpi,
|
|
Controller,
|
|
&DevicePathLength,
|
|
&DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",
|
|
__FUNCTION__, Controller
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Check validity of the device path of the ATA AHCI controller.
|
|
//
|
|
Status = AhciIsHcDevicePathValid (DevicePath, DevicePathLength);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",
|
|
__FUNCTION__, Controller
|
|
));
|
|
Controller++;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// For S3 resume performance consideration, not all ports on an ATA AHCI
|
|
// controller will be enumerated/initialized. The driver consumes the
|
|
// content within S3StorageDeviceInitList LockBox to get the ports that
|
|
// will be enumerated/initialized during S3 resume.
|
|
//
|
|
if (BootMode == BOOT_ON_S3_RESUME) {
|
|
NumberOfPorts = AhciS3GetEumeratePorts (DevicePath, DevicePathLength, &PortBitMap);
|
|
if (NumberOfPorts == 0) {
|
|
//
|
|
// No ports need to be enumerated for this controller.
|
|
//
|
|
Controller++;
|
|
continue;
|
|
}
|
|
} else {
|
|
PortBitMap = MAX_UINT32;
|
|
}
|
|
|
|
//
|
|
// Memory allocation for controller private data.
|
|
//
|
|
Private = AllocateZeroPool (sizeof (PEI_AHCI_CONTROLLER_PRIVATE_DATA));
|
|
if (Private == NULL) {
|
|
DEBUG ((
|
|
DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",
|
|
__FUNCTION__, Controller
|
|
));
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Initialize controller private data.
|
|
//
|
|
Private->Signature = AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;
|
|
Private->MmioBase = MmioBase;
|
|
Private->DevicePathLength = DevicePathLength;
|
|
Private->DevicePath = DevicePath;
|
|
Private->PortBitMap = PortBitMap;
|
|
InitializeListHead (&Private->DeviceList);
|
|
|
|
Status = AhciModeInitialization (Private);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: Controller initialization fail for Controller %d with Status - %r.\n",
|
|
__FUNCTION__,
|
|
Controller,
|
|
Status
|
|
));
|
|
Controller++;
|
|
continue;
|
|
}
|
|
|
|
Private->AtaPassThruMode.Attributes = EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL |
|
|
EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL;
|
|
Private->AtaPassThruMode.IoAlign = sizeof (UINTN);
|
|
Private->AtaPassThruPpi.Revision = EDKII_PEI_ATA_PASS_THRU_PPI_REVISION;
|
|
Private->AtaPassThruPpi.Mode = &Private->AtaPassThruMode;
|
|
Private->AtaPassThruPpi.PassThru = AhciAtaPassThruPassThru;
|
|
Private->AtaPassThruPpi.GetNextPort = AhciAtaPassThruGetNextPort;
|
|
Private->AtaPassThruPpi.GetNextDevice = AhciAtaPassThruGetNextDevice;
|
|
Private->AtaPassThruPpi.GetDevicePath = AhciAtaPassThruGetDevicePath;
|
|
CopyMem (
|
|
&Private->AtaPassThruPpiList,
|
|
&mAhciAtaPassThruPpiListTemplate,
|
|
sizeof (EFI_PEI_PPI_DESCRIPTOR)
|
|
);
|
|
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,
|
|
"%a: Security Security Command PPI will be produced for Controller %d.\n",
|
|
__FUNCTION__, Controller
|
|
));
|
|
Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;
|
|
Private->StorageSecurityPpi.GetNumberofDevices = AhciStorageSecurityGetDeviceNo;
|
|
Private->StorageSecurityPpi.GetDevicePath = AhciStorageSecurityGetDevicePath;
|
|
Private->StorageSecurityPpi.ReceiveData = AhciStorageSecurityReceiveData;
|
|
Private->StorageSecurityPpi.SendData = AhciStorageSecuritySendData;
|
|
CopyMem (
|
|
&Private->StorageSecurityPpiList,
|
|
&mAhciStorageSecurityPpiListTemplate,
|
|
sizeof (EFI_PEI_PPI_DESCRIPTOR)
|
|
);
|
|
Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;
|
|
PeiServicesInstallPpi (&Private->StorageSecurityPpiList);
|
|
}
|
|
|
|
CopyMem (
|
|
&Private->EndOfPeiNotifyList,
|
|
&mAhciEndOfPeiNotifyListTemplate,
|
|
sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)
|
|
);
|
|
PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);
|
|
|
|
DEBUG ((
|
|
DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",
|
|
__FUNCTION__, Controller
|
|
));
|
|
Controller++;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|