2018-02-11 04:00:44 +01:00
|
|
|
/** @file
|
|
|
|
Opal Password PEI driver which is used to unlock Opal Password for S3.
|
|
|
|
|
|
|
|
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
|
|
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"
|
|
|
|
|
|
|
|
EFI_GUID mOpalDeviceAtaGuid = OPAL_DEVICE_ATA_GUID;
|
|
|
|
EFI_GUID mOpalDeviceNvmeGuid = OPAL_DEVICE_NVME_GUID;
|
|
|
|
|
|
|
|
#define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)
|
|
|
|
#define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)
|
|
|
|
|
|
|
|
/**
|
|
|
|
Get IOMMU PPI.
|
|
|
|
|
|
|
|
@return Pointer to IOMMU PPI.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EDKII_IOMMU_PPI *
|
|
|
|
GetIoMmu (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EDKII_IOMMU_PPI *IoMmu;
|
|
|
|
|
|
|
|
IoMmu = NULL;
|
|
|
|
Status = PeiServicesLocatePpi (
|
|
|
|
&gEdkiiIoMmuPpiGuid,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
(VOID **) &IoMmu
|
|
|
|
);
|
|
|
|
if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
|
|
|
|
return IoMmu;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
|
|
|
|
OperationBusMasterCommonBuffer64 mapping.
|
|
|
|
|
|
|
|
@param Pages The number of pages to allocate.
|
|
|
|
@param HostAddress A pointer to store the base system memory address of the
|
|
|
|
allocated range.
|
|
|
|
@param DeviceAddress The resulting map address for the bus master PCI controller to use to
|
|
|
|
access the hosts HostAddress.
|
|
|
|
@param Mapping A resulting value to pass to Unmap().
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The requested memory pages were allocated.
|
|
|
|
@retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
|
|
|
|
MEMORY_WRITE_COMBINE and MEMORY_CACHED.
|
|
|
|
@retval EFI_INVALID_PARAMETER One or more parameters are invalid.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
IoMmuAllocateBuffer (
|
|
|
|
IN UINTN Pages,
|
|
|
|
OUT VOID **HostAddress,
|
|
|
|
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
|
|
|
|
OUT VOID **Mapping
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN NumberOfBytes;
|
|
|
|
EFI_PHYSICAL_ADDRESS HostPhyAddress;
|
|
|
|
EDKII_IOMMU_PPI *IoMmu;
|
|
|
|
|
|
|
|
*HostAddress = NULL;
|
|
|
|
*DeviceAddress = 0;
|
|
|
|
*Mapping = NULL;
|
|
|
|
|
|
|
|
IoMmu = GetIoMmu ();
|
|
|
|
|
|
|
|
if (IoMmu != NULL) {
|
|
|
|
Status = IoMmu->AllocateBuffer (
|
|
|
|
IoMmu,
|
|
|
|
EfiBootServicesData,
|
|
|
|
Pages,
|
|
|
|
HostAddress,
|
|
|
|
0
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
|
|
|
|
Status = IoMmu->Map (
|
|
|
|
IoMmu,
|
|
|
|
EdkiiIoMmuOperationBusMasterCommonBuffer,
|
|
|
|
*HostAddress,
|
|
|
|
&NumberOfBytes,
|
|
|
|
DeviceAddress,
|
|
|
|
Mapping
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
|
|
|
|
*HostAddress = NULL;
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
Status = IoMmu->SetAttribute (
|
|
|
|
IoMmu,
|
|
|
|
*Mapping,
|
|
|
|
EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
IoMmu->Unmap (IoMmu, *Mapping);
|
|
|
|
IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
|
|
|
|
*Mapping = NULL;
|
|
|
|
*HostAddress = NULL;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Status = PeiServicesAllocatePages (
|
|
|
|
EfiBootServicesData,
|
|
|
|
Pages,
|
|
|
|
&HostPhyAddress
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
*HostAddress = (VOID *) (UINTN) HostPhyAddress;
|
|
|
|
*DeviceAddress = HostPhyAddress;
|
|
|
|
*Mapping = NULL;
|
|
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Frees memory that was allocated with AllocateBuffer().
|
|
|
|
|
|
|
|
@param Pages The number of pages to free.
|
|
|
|
@param HostAddress The base system memory address of the allocated range.
|
|
|
|
@param Mapping The mapping value returned from Map().
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
IoMmuFreeBuffer (
|
|
|
|
IN UINTN Pages,
|
|
|
|
IN VOID *HostAddress,
|
|
|
|
IN VOID *Mapping
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EDKII_IOMMU_PPI *IoMmu;
|
|
|
|
|
|
|
|
IoMmu = GetIoMmu ();
|
|
|
|
|
|
|
|
if (IoMmu != NULL) {
|
|
|
|
IoMmu->SetAttribute (IoMmu, Mapping, 0);
|
|
|
|
IoMmu->Unmap (IoMmu, Mapping);
|
|
|
|
IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
|
|
|
|
} else {
|
|
|
|
PeiServicesFreePages (
|
|
|
|
(EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
|
|
|
|
Pages
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Provide IO action support.
|
|
|
|
|
|
|
|
@param[in] PeiDev The opal device need to perform trusted IO.
|
|
|
|
@param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.
|
|
|
|
@param[in] SecurityProtocol Security Protocol
|
|
|
|
@param[in] SpSpecific Security Protocol Specific
|
|
|
|
@param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512
|
|
|
|
@param[in] Buffer Address of Data to transfer
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Perform the IO action success.
|
|
|
|
@retval Others Perform the IO action failed.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
PerformTrustedIo (
|
|
|
|
OPAL_PEI_DEVICE *PeiDev,
|
|
|
|
OPAL_IO_TYPE IoType,
|
|
|
|
UINT8 SecurityProtocol,
|
|
|
|
UINT16 SpSpecific,
|
|
|
|
UINTN TransferLength,
|
|
|
|
VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN BufferSizeBlocks;
|
|
|
|
EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
|
|
|
|
OPAL_DEVICE_ATA *DevInfoAta;
|
|
|
|
AHCI_CONTEXT *AhciContext;
|
|
|
|
NVME_CONTEXT *NvmeContext;
|
|
|
|
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_ATA) {
|
|
|
|
DevInfoAta = (OPAL_DEVICE_ATA *) PeiDev->Device;
|
|
|
|
AhciContext = (AHCI_CONTEXT *) PeiDev->Context;
|
|
|
|
|
|
|
|
BufferSizeBlocks = TransferLength / 512;
|
|
|
|
|
|
|
|
ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );
|
|
|
|
AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;
|
|
|
|
AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;
|
|
|
|
AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );
|
|
|
|
AtaCommandBlock.AtaFeatures = SecurityProtocol;
|
|
|
|
AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );
|
|
|
|
AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );
|
|
|
|
AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;
|
|
|
|
|
|
|
|
|
|
|
|
ZeroMem( AhciContext->Buffer, HDD_PAYLOAD );
|
|
|
|
ASSERT( TransferLength <= HDD_PAYLOAD );
|
|
|
|
|
|
|
|
if (IoType == OpalSend) {
|
|
|
|
CopyMem( AhciContext->Buffer, Buffer, TransferLength );
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = AhciPioTransfer(
|
|
|
|
AhciContext,
|
|
|
|
(UINT8) DevInfoAta->Port,
|
|
|
|
(UINT8) DevInfoAta->PortMultiplierPort,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction
|
|
|
|
&AtaCommandBlock,
|
|
|
|
NULL,
|
|
|
|
AhciContext->Buffer,
|
|
|
|
(UINT32)TransferLength,
|
|
|
|
ATA_TIMEOUT
|
|
|
|
);
|
|
|
|
|
|
|
|
if (IoType == OpalRecv) {
|
|
|
|
CopyMem( Buffer, AhciContext->Buffer, TransferLength );
|
|
|
|
}
|
|
|
|
} else if (PeiDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
|
|
|
|
NvmeContext = (NVME_CONTEXT *) PeiDev->Context;
|
|
|
|
Status = NvmeSecuritySendReceive (
|
|
|
|
NvmeContext,
|
|
|
|
IoType == OpalSend,
|
|
|
|
SecurityProtocol,
|
|
|
|
SwapBytes16(SpSpecific),
|
|
|
|
TransferLength,
|
|
|
|
Buffer
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", PeiDev->DeviceType));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Send a security protocol command to a device that receives data and/or the result
|
|
|
|
of one or more commands sent by SendData.
|
|
|
|
|
|
|
|
The ReceiveData function sends a security protocol command to the given MediaId.
|
|
|
|
The security protocol command sent is defined by SecurityProtocolId and contains
|
|
|
|
the security protocol specific data SecurityProtocolSpecificData. The function
|
|
|
|
returns the data from the security protocol command in PayloadBuffer.
|
|
|
|
|
|
|
|
For devices supporting the SCSI command set, the security protocol command is sent
|
|
|
|
using the SECURITY PROTOCOL IN command defined in SPC-4.
|
|
|
|
|
|
|
|
For devices supporting the ATA command set, the security protocol command is sent
|
|
|
|
using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
|
|
|
|
is non-zero.
|
|
|
|
|
|
|
|
If the PayloadBufferSize is zero, the security protocol command is sent using the
|
|
|
|
Trusted Non-Data command defined in ATA8-ACS.
|
|
|
|
|
|
|
|
If PayloadBufferSize is too small to store the available data from the security
|
|
|
|
protocol command, the function shall copy PayloadBufferSize bytes into the
|
|
|
|
PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
|
|
|
|
|
|
|
|
If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
|
|
|
|
the function shall return EFI_INVALID_PARAMETER.
|
|
|
|
|
|
|
|
If the given MediaId does not support security protocol commands, the function shall
|
|
|
|
return EFI_UNSUPPORTED. If there is no media in the device, the function returns
|
|
|
|
EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
|
|
|
|
the function returns EFI_MEDIA_CHANGED.
|
|
|
|
|
|
|
|
If the security protocol fails to complete within the Timeout period, the function
|
|
|
|
shall return EFI_TIMEOUT.
|
|
|
|
|
|
|
|
If the security protocol command completes without an error, the function shall
|
|
|
|
return EFI_SUCCESS. If the security protocol command completes with an error, the
|
|
|
|
function shall return EFI_DEVICE_ERROR.
|
|
|
|
|
|
|
|
@param This Indicates a pointer to the calling context.
|
|
|
|
@param MediaId ID of the medium to receive data from.
|
|
|
|
@param Timeout The timeout, in 100ns units, to use for the execution
|
|
|
|
of the security protocol command. A Timeout value of 0
|
|
|
|
means that this function will wait indefinitely for the
|
|
|
|
security protocol command to execute. If Timeout is greater
|
|
|
|
than zero, then this function will return EFI_TIMEOUT
|
|
|
|
if the time required to execute the receive data command
|
|
|
|
is greater than Timeout.
|
|
|
|
@param SecurityProtocolId The value of the "Security Protocol" parameter of
|
|
|
|
the security protocol command to be sent.
|
|
|
|
@param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
|
|
|
|
of the security protocol command to be sent.
|
|
|
|
@param PayloadBufferSize Size in bytes of the payload data buffer.
|
|
|
|
@param PayloadBuffer A pointer to a destination buffer to store the security
|
|
|
|
protocol command specific payload data for the security
|
|
|
|
protocol command. The caller is responsible for having
|
|
|
|
either implicit or explicit ownership of the buffer.
|
|
|
|
@param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
|
|
|
|
data written to the payload data buffer.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The security protocol command completed successfully.
|
|
|
|
@retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
|
|
|
|
data from the device. The PayloadBuffer contains the truncated data.
|
|
|
|
@retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
|
|
|
|
@retval EFI_DEVICE_ERROR The security protocol command completed with an error.
|
|
|
|
@retval EFI_NO_MEDIA There is no media in the device.
|
|
|
|
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
|
|
|
|
@retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
|
|
|
|
PayloadBufferSize is non-zero.
|
|
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the security
|
|
|
|
protocol command to execute.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SecurityReceiveData (
|
|
|
|
IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN UINT64 Timeout,
|
|
|
|
IN UINT8 SecurityProtocolId,
|
|
|
|
IN UINT16 SecurityProtocolSpecificData,
|
|
|
|
IN UINTN PayloadBufferSize,
|
|
|
|
OUT VOID *PayloadBuffer,
|
|
|
|
OUT UINTN *PayloadTransferSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
OPAL_PEI_DEVICE *PeiDev;
|
|
|
|
|
|
|
|
PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);
|
|
|
|
if (PeiDev == NULL) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PerformTrustedIo (
|
|
|
|
PeiDev,
|
|
|
|
OpalRecv,
|
|
|
|
SecurityProtocolId,
|
|
|
|
SecurityProtocolSpecificData,
|
|
|
|
PayloadBufferSize,
|
|
|
|
PayloadBuffer
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Send a security protocol command to a device.
|
|
|
|
|
|
|
|
The SendData function sends a security protocol command containing the payload
|
|
|
|
PayloadBuffer to the given MediaId. The security protocol command sent is
|
|
|
|
defined by SecurityProtocolId and contains the security protocol specific data
|
|
|
|
SecurityProtocolSpecificData. If the underlying protocol command requires a
|
|
|
|
specific padding for the command payload, the SendData function shall add padding
|
|
|
|
bytes to the command payload to satisfy the padding requirements.
|
|
|
|
|
|
|
|
For devices supporting the SCSI command set, the security protocol command is sent
|
|
|
|
using the SECURITY PROTOCOL OUT command defined in SPC-4.
|
|
|
|
|
|
|
|
For devices supporting the ATA command set, the security protocol command is sent
|
|
|
|
using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
|
|
|
|
is non-zero. If the PayloadBufferSize is zero, the security protocol command is
|
|
|
|
sent using the Trusted Non-Data command defined in ATA8-ACS.
|
|
|
|
|
|
|
|
If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
|
|
|
|
return EFI_INVALID_PARAMETER.
|
|
|
|
|
|
|
|
If the given MediaId does not support security protocol commands, the function
|
|
|
|
shall return EFI_UNSUPPORTED. If there is no media in the device, the function
|
|
|
|
returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
|
|
|
|
device, the function returns EFI_MEDIA_CHANGED.
|
|
|
|
|
|
|
|
If the security protocol fails to complete within the Timeout period, the function
|
|
|
|
shall return EFI_TIMEOUT.
|
|
|
|
|
|
|
|
If the security protocol command completes without an error, the function shall return
|
|
|
|
EFI_SUCCESS. If the security protocol command completes with an error, the function
|
|
|
|
shall return EFI_DEVICE_ERROR.
|
|
|
|
|
|
|
|
@param This Indicates a pointer to the calling context.
|
|
|
|
@param MediaId ID of the medium to receive data from.
|
|
|
|
@param Timeout The timeout, in 100ns units, to use for the execution
|
|
|
|
of the security protocol command. A Timeout value of 0
|
|
|
|
means that this function will wait indefinitely for the
|
|
|
|
security protocol command to execute. If Timeout is greater
|
|
|
|
than zero, then this function will return EFI_TIMEOUT
|
|
|
|
if the time required to execute the send data command
|
|
|
|
is greater than Timeout.
|
|
|
|
@param SecurityProtocolId The value of the "Security Protocol" parameter of
|
|
|
|
the security protocol command to be sent.
|
|
|
|
@param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
|
|
|
|
of the security protocol command to be sent.
|
|
|
|
@param PayloadBufferSize Size in bytes of the payload data buffer.
|
|
|
|
@param PayloadBuffer A pointer to a destination buffer to store the security
|
|
|
|
protocol command specific payload data for the security
|
|
|
|
protocol command.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The security protocol command completed successfully.
|
|
|
|
@retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
|
|
|
|
@retval EFI_DEVICE_ERROR The security protocol command completed with an error.
|
|
|
|
@retval EFI_NO_MEDIA There is no media in the device.
|
|
|
|
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
|
|
|
|
@retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
|
|
|
|
@retval EFI_TIMEOUT A timeout occurred while waiting for the security
|
|
|
|
protocol command to execute.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
SecuritySendData (
|
|
|
|
IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
|
|
|
|
IN UINT32 MediaId,
|
|
|
|
IN UINT64 Timeout,
|
|
|
|
IN UINT8 SecurityProtocolId,
|
|
|
|
IN UINT16 SecurityProtocolSpecificData,
|
|
|
|
IN UINTN PayloadBufferSize,
|
|
|
|
IN VOID *PayloadBuffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
OPAL_PEI_DEVICE *PeiDev;
|
|
|
|
|
|
|
|
PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This);
|
|
|
|
if (PeiDev == NULL) {
|
|
|
|
return EFI_DEVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PerformTrustedIo (
|
|
|
|
PeiDev,
|
|
|
|
OpalSend,
|
|
|
|
SecurityProtocolId,
|
|
|
|
SecurityProtocolSpecificData,
|
|
|
|
PayloadBufferSize,
|
|
|
|
PayloadBuffer
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Save/Restore RootPort configuration space.
|
|
|
|
|
|
|
|
@param[in] DevInfoNvme Pointer to NVMe device info.
|
|
|
|
@param[in] SaveAction TRUE: Save, FALSE: Restore
|
|
|
|
@param[in,out] PcieConfBufferList Configuration space data buffer for save/restore
|
|
|
|
|
|
|
|
@return PCIE base address of this RootPort
|
|
|
|
**/
|
|
|
|
UINTN
|
|
|
|
SaveRestoreRootportConfSpace (
|
|
|
|
IN OPAL_DEVICE_NVME *DevInfoNvme,
|
|
|
|
IN BOOLEAN SaveAction,
|
|
|
|
IN OUT UINT8 **PcieConfBufferList
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN RpBase;
|
|
|
|
UINTN Length;
|
|
|
|
OPAL_PCI_DEVICE *DevNode;
|
|
|
|
UINT8 *StorePcieConfData;
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
Length = 0;
|
|
|
|
Index = 0;
|
|
|
|
RpBase = 0;
|
|
|
|
|
|
|
|
while (sizeof (OPAL_DEVICE_NVME) + Length < DevInfoNvme->Length) {
|
|
|
|
DevNode = (OPAL_PCI_DEVICE *)((UINT8*)DevInfoNvme->PciBridgeNode + Length);
|
|
|
|
RpBase = PCI_LIB_ADDRESS (DevNode->Bus, DevNode->Device, DevNode->Function, 0x0);
|
|
|
|
|
|
|
|
if (PcieConfBufferList != NULL) {
|
|
|
|
if (SaveAction) {
|
|
|
|
StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);
|
|
|
|
ASSERT (StorePcieConfData != NULL);
|
|
|
|
OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);
|
|
|
|
PcieConfBufferList[Index] = StorePcieConfData;
|
|
|
|
} else {
|
|
|
|
// Skip PCIe Command & Status registers
|
|
|
|
StorePcieConfData = PcieConfBufferList[Index];
|
|
|
|
OpalPciWrite (RpBase, StorePcieConfData, 4);
|
|
|
|
OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8);
|
|
|
|
|
|
|
|
FreePool (StorePcieConfData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Length += sizeof (OPAL_PCI_DEVICE);
|
|
|
|
Index ++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RpBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Configure RootPort for downstream PCIe NAND devices.
|
|
|
|
|
|
|
|
@param[in] RpBase - PCIe configuration space address of this RootPort
|
|
|
|
@param[in] BusNumber - Bus number
|
|
|
|
@param[in] MemoryBase - Memory base address
|
|
|
|
@param[in] MemoryLength - Memory size
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
ConfigureRootPortForPcieNand (
|
|
|
|
IN UINTN RpBase,
|
|
|
|
IN UINTN BusNumber,
|
|
|
|
IN UINT32 MemoryBase,
|
|
|
|
IN UINT32 MemoryLength
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT32 MemoryLimit;
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",
|
|
|
|
BusNumber, MemoryBase, MemoryLength));
|
|
|
|
|
|
|
|
if (MemoryLength == 0) {
|
|
|
|
MemoryLimit = MemoryBase;
|
|
|
|
} else {
|
|
|
|
MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Configue PCIE configuration space for RootPort
|
|
|
|
///
|
|
|
|
PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers
|
|
|
|
PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers
|
|
|
|
PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers
|
|
|
|
PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers
|
|
|
|
PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register
|
|
|
|
PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register
|
|
|
|
PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers
|
|
|
|
PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers
|
|
|
|
PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers
|
|
|
|
PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
The function returns whether or not the device is Opal Locked.
|
|
|
|
TRUE means that the device is partially or fully locked.
|
|
|
|
This will perform a Level 0 Discovery and parse the locking feature descriptor
|
|
|
|
|
|
|
|
@param[in] OpalDev Opal object to determine if locked.
|
|
|
|
@param[out] BlockSidSupported Whether device support BlockSid feature.
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
IsOpalDeviceLocked(
|
|
|
|
OPAL_PEI_DEVICE *OpalDev,
|
|
|
|
BOOLEAN *BlockSidSupported
|
|
|
|
)
|
|
|
|
{
|
|
|
|
OPAL_SESSION Session;
|
|
|
|
OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;
|
|
|
|
TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;
|
|
|
|
UINT16 OpalBaseComId;
|
|
|
|
TCG_RESULT Ret;
|
|
|
|
|
|
|
|
Session.Sscp = &OpalDev->Sscp;
|
|
|
|
Session.MediaId = 0;
|
|
|
|
|
|
|
|
Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);
|
|
|
|
if (Ret != TcgResultSuccess) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Session.OpalBaseComId = OpalBaseComId;
|
|
|
|
*BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE;
|
|
|
|
|
|
|
|
Ret = OpalGetLockingInfo(&Session, &LockingFeature);
|
|
|
|
if (Ret != TcgResultSuccess) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Unlock OPAL password for S3.
|
|
|
|
|
|
|
|
@param[in] OpalDev Opal object to unlock.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
UnlockOpalPassword (
|
|
|
|
IN OPAL_PEI_DEVICE *OpalDev
|
|
|
|
)
|
|
|
|
{
|
|
|
|
TCG_RESULT Result;
|
|
|
|
OPAL_SESSION Session;
|
|
|
|
BOOLEAN BlockSidSupport;
|
|
|
|
UINT32 PpStorageFlags;
|
|
|
|
BOOLEAN BlockSIDEnabled;
|
|
|
|
|
|
|
|
BlockSidSupport = FALSE;
|
|
|
|
if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {
|
|
|
|
ZeroMem(&Session, sizeof (Session));
|
|
|
|
Session.Sscp = &OpalDev->Sscp;
|
|
|
|
Session.MediaId = 0;
|
|
|
|
Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;
|
|
|
|
|
|
|
|
Result = OpalUtilUpdateGlobalLockingRange (
|
|
|
|
&Session,
|
|
|
|
OpalDev->Device->Password,
|
|
|
|
OpalDev->Device->PasswordLength,
|
|
|
|
FALSE,
|
|
|
|
FALSE
|
|
|
|
);
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"%a() OpalUtilUpdateGlobalLockingRange() Result = 0x%x\n",
|
|
|
|
__FUNCTION__,
|
|
|
|
Result
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
PpStorageFlags = Tcg2PhysicalPresenceLibGetManagementFlags ();
|
|
|
|
if ((PpStorageFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
|
|
|
|
BlockSIDEnabled = TRUE;
|
|
|
|
} else {
|
|
|
|
BlockSIDEnabled = FALSE;
|
|
|
|
}
|
|
|
|
if (BlockSIDEnabled && BlockSidSupport) {
|
2018-05-07 07:27:40 +02:00
|
|
|
DEBUG ((DEBUG_INFO, "OpalPassword: S3 phase send BlockSid command to device!\n"));
|
2018-02-11 04:00:44 +01:00
|
|
|
ZeroMem(&Session, sizeof (Session));
|
|
|
|
Session.Sscp = &OpalDev->Sscp;
|
|
|
|
Session.MediaId = 0;
|
|
|
|
Session.OpalBaseComId = OpalDev->Device->OpalBaseComId;
|
|
|
|
Result = OpalBlockSid (&Session, TRUE);
|
|
|
|
DEBUG ((
|
|
|
|
DEBUG_INFO,
|
|
|
|
"%a() OpalBlockSid() Result = 0x%x\n",
|
|
|
|
__FUNCTION__,
|
|
|
|
Result
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Unlock ATA OPAL password for S3.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
UnlockOpalPasswordAta (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT8 *DevInfo;
|
|
|
|
OPAL_DEVICE_ATA TempDevInfoAta;
|
|
|
|
OPAL_DEVICE_ATA *DevInfoAta;
|
|
|
|
UINTN DevInfoLengthAta;
|
|
|
|
UINT8 Bus;
|
|
|
|
UINT8 Device;
|
|
|
|
UINT8 Function;
|
|
|
|
OPAL_PEI_DEVICE OpalDev;
|
|
|
|
UINT8 BaseClassCode;
|
|
|
|
UINT8 SubClassCode;
|
|
|
|
UINT8 SataCmdSt;
|
|
|
|
AHCI_CONTEXT AhciContext;
|
|
|
|
UINT32 AhciBar;
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get ATA OPAL device info from LockBox.
|
|
|
|
//
|
|
|
|
DevInfo = (UINT8 *) &TempDevInfoAta;
|
|
|
|
DevInfoLengthAta = sizeof (OPAL_DEVICE_ATA);
|
|
|
|
Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthAta));
|
|
|
|
if (DevInfo != NULL) {
|
|
|
|
Status = RestoreLockBox (&mOpalDeviceAtaGuid, DevInfo, &DevInfoLengthAta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (EFI_ERROR (Status) || (DevInfo == NULL)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (DevInfoAta = (OPAL_DEVICE_ATA *) DevInfo;
|
|
|
|
(UINTN) DevInfoAta < ((UINTN) DevInfo + DevInfoLengthAta);
|
|
|
|
DevInfoAta = (OPAL_DEVICE_ATA *) ((UINTN) DevInfoAta + DevInfoAta->Length)) {
|
|
|
|
Bus = DevInfoAta->Device.Bus;
|
|
|
|
Device = DevInfoAta->Device.Device;
|
|
|
|
Function = DevInfoAta->Device.Function;
|
|
|
|
|
|
|
|
SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET));
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), 0x6);
|
|
|
|
|
|
|
|
BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
|
|
|
|
SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
|
|
|
|
if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||
|
|
|
|
((SubClassCode != PCI_CLASS_MASS_STORAGE_SATADPA) && (SubClassCode != PCI_CLASS_MASS_STORAGE_RAID))) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode are not supported\n", __FUNCTION__));
|
|
|
|
} else {
|
|
|
|
AhciBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));
|
|
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), DevInfoAta->BarAddr);
|
|
|
|
|
|
|
|
ZeroMem (&AhciContext, sizeof (AHCI_CONTEXT));
|
|
|
|
AhciContext.AhciBar = DevInfoAta->BarAddr;
|
|
|
|
AhciAllocateResource (&AhciContext);
|
|
|
|
Status = AhciModeInitialize (&AhciContext, (UINT8)DevInfoAta->Port);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "%a() AhciModeInitialize() error, Status: %r\n", __FUNCTION__, Status));
|
2018-03-13 08:41:41 +01:00
|
|
|
} else {
|
|
|
|
OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;
|
|
|
|
OpalDev.Sscp.ReceiveData = SecurityReceiveData;
|
|
|
|
OpalDev.Sscp.SendData = SecuritySendData;
|
|
|
|
OpalDev.DeviceType = OPAL_DEVICE_TYPE_ATA;
|
|
|
|
OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoAta;
|
|
|
|
OpalDev.Context = &AhciContext;
|
|
|
|
|
|
|
|
UnlockOpalPassword (&OpalDev);
|
2018-02-11 04:00:44 +01:00
|
|
|
}
|
|
|
|
AhciFreeResource (&AhciContext);
|
|
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), AhciBar);
|
|
|
|
}
|
|
|
|
PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), SataCmdSt);
|
|
|
|
}
|
|
|
|
|
|
|
|
ZeroMem (DevInfo, DevInfoLengthAta);
|
|
|
|
if ((UINTN) DevInfo != (UINTN) &TempDevInfoAta) {
|
|
|
|
FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthAta));
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Unlock NVMe OPAL password for S3.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
UnlockOpalPasswordNvme (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT8 *DevInfo;
|
|
|
|
OPAL_DEVICE_NVME TempDevInfoNvme;
|
|
|
|
OPAL_DEVICE_NVME *DevInfoNvme;
|
|
|
|
UINTN DevInfoLengthNvme;
|
|
|
|
UINT8 Bus;
|
|
|
|
UINT8 Device;
|
|
|
|
UINT8 Function;
|
|
|
|
OPAL_PEI_DEVICE OpalDev;
|
|
|
|
UINT8 BaseClassCode;
|
|
|
|
UINT8 SubClassCode;
|
|
|
|
UINT8 ProgInt;
|
|
|
|
UINT8 NvmeCmdSt;
|
|
|
|
UINT8 *StorePcieConfDataList[16];
|
|
|
|
UINTN RpBase;
|
|
|
|
UINTN MemoryBase;
|
|
|
|
UINTN MemoryLength;
|
|
|
|
NVME_CONTEXT NvmeContext;
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__));
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get NVMe OPAL device info from LockBox.
|
|
|
|
//
|
|
|
|
DevInfo = (UINT8 *) &TempDevInfoNvme;
|
|
|
|
DevInfoLengthNvme = sizeof (OPAL_DEVICE_NVME);
|
|
|
|
Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
DevInfo = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLengthNvme));
|
|
|
|
if (DevInfo != NULL) {
|
|
|
|
Status = RestoreLockBox (&mOpalDeviceNvmeGuid, DevInfo, &DevInfoLengthNvme);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (EFI_ERROR (Status) || (DevInfo == NULL)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (DevInfoNvme = (OPAL_DEVICE_NVME *) DevInfo;
|
|
|
|
(UINTN) DevInfoNvme < ((UINTN) DevInfo + DevInfoLengthNvme);
|
|
|
|
DevInfoNvme = (OPAL_DEVICE_NVME *) ((UINTN) DevInfoNvme + DevInfoNvme->Length)) {
|
|
|
|
Bus = DevInfoNvme->Device.Bus;
|
|
|
|
Device = DevInfoNvme->Device.Device;
|
|
|
|
Function = DevInfoNvme->Device.Function;
|
|
|
|
|
|
|
|
RpBase = 0;
|
|
|
|
NvmeCmdSt = 0;
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Save original RootPort configuration space to heap
|
|
|
|
///
|
|
|
|
RpBase = SaveRestoreRootportConfSpace (
|
|
|
|
DevInfoNvme,
|
|
|
|
TRUE, // save
|
|
|
|
StorePcieConfDataList
|
|
|
|
);
|
|
|
|
MemoryBase = DevInfoNvme->BarAddr;
|
|
|
|
MemoryLength = 0;
|
|
|
|
ConfigureRootPortForPcieNand (RpBase, Bus, (UINT32) MemoryBase, (UINT32) MemoryLength);
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Enable PCIE decode for RootPort
|
|
|
|
///
|
|
|
|
NvmeCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);
|
|
|
|
PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);
|
|
|
|
|
|
|
|
BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));
|
|
|
|
SubClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));
|
|
|
|
ProgInt = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x09));
|
|
|
|
if ((BaseClassCode != PCI_CLASS_MASS_STORAGE) ||
|
|
|
|
(SubClassCode != PCI_CLASS_MASS_STORAGE_NVM) ||
|
|
|
|
(ProgInt != PCI_IF_NVMHCI)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "%a() ClassCode/SubClassCode/PI are not supported\n", __FUNCTION__));
|
|
|
|
} else {
|
|
|
|
ZeroMem (&NvmeContext, sizeof (NVME_CONTEXT));
|
|
|
|
NvmeContext.Nbar = DevInfoNvme->BarAddr;
|
|
|
|
NvmeContext.PciBase = PCI_LIB_ADDRESS (Bus, Device, Function, 0x0);
|
|
|
|
NvmeContext.NvmeInitWaitTime = 0;
|
|
|
|
NvmeContext.Nsid = DevInfoNvme->NvmeNamespaceId;
|
|
|
|
NvmeAllocateResource (&NvmeContext);
|
|
|
|
Status = NvmeControllerInit (&NvmeContext);
|
|
|
|
|
|
|
|
OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE;
|
|
|
|
OpalDev.Sscp.ReceiveData = SecurityReceiveData;
|
|
|
|
OpalDev.Sscp.SendData = SecuritySendData;
|
|
|
|
OpalDev.DeviceType = OPAL_DEVICE_TYPE_NVME;
|
|
|
|
OpalDev.Device = (OPAL_DEVICE_COMMON *) DevInfoNvme;
|
|
|
|
OpalDev.Context = &NvmeContext;
|
|
|
|
|
|
|
|
UnlockOpalPassword (&OpalDev);
|
|
|
|
|
|
|
|
Status = NvmeControllerExit (&NvmeContext);
|
|
|
|
NvmeFreeResource (&NvmeContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT (RpBase != 0);
|
|
|
|
PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);
|
|
|
|
RpBase = SaveRestoreRootportConfSpace (
|
|
|
|
DevInfoNvme,
|
|
|
|
FALSE, // restore
|
|
|
|
StorePcieConfDataList
|
|
|
|
);
|
|
|
|
PciWrite8 (RpBase + NVME_PCIE_PCICMD, NvmeCmdSt);
|
|
|
|
}
|
|
|
|
|
|
|
|
ZeroMem (DevInfo, DevInfoLengthNvme);
|
|
|
|
if ((UINTN) DevInfo != (UINTN) &TempDevInfoNvme) {
|
|
|
|
FreePages (DevInfo, EFI_SIZE_TO_PAGES (DevInfoLengthNvme));
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Unlock OPAL password for S3.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
OpalPasswordS3 (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UnlockOpalPasswordAta ();
|
|
|
|
UnlockOpalPasswordNvme ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Entry point of the notification callback function itself within the PEIM.
|
|
|
|
It is to unlock OPAL password for S3.
|
|
|
|
|
|
|
|
@param PeiServices Indirect reference to the PEI Services Table.
|
|
|
|
@param NotifyDescriptor Address of the notification descriptor data structure.
|
|
|
|
@param Ppi Address of the PPI that was installed.
|
|
|
|
|
|
|
|
@return Status of the notification.
|
|
|
|
The status code returned from this function is ignored.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
OpalPasswordEndOfPeiNotify(
|
|
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
|
|
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
|
|
|
|
IN VOID *Ppi
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_BOOT_MODE BootMode;
|
|
|
|
|
|
|
|
Status = PeiServicesGetBootMode (&BootMode);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (BootMode != BOOT_ON_S3_RESUME) {
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "%a() - enter at S3 resume\n", __FUNCTION__));
|
|
|
|
|
|
|
|
OpalPasswordS3 ();
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "%a() - exit at S3 resume\n", __FUNCTION__));
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordEndOfPeiNotifyDesc = {
|
|
|
|
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
|
|
&gEfiEndOfPeiSignalPpiGuid,
|
|
|
|
OpalPasswordEndOfPeiNotify
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
Main entry for this module.
|
|
|
|
|
|
|
|
@param FileHandle Handle of the file being invoked.
|
|
|
|
@param PeiServices Pointer to PEI Services table.
|
|
|
|
|
|
|
|
@return Status from PeiServicesNotifyPpi.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
OpalPasswordPeiInit (
|
|
|
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = PeiServicesNotifyPpi (&mOpalPasswordEndOfPeiNotifyDesc);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|