mirror of https://github.com/acidanthera/audk.git
375 lines
11 KiB
C
375 lines
11 KiB
C
/** @file
|
|
TCG MOR (Memory Overwrite Request) Control Driver.
|
|
|
|
This driver initialize MemoryOverwriteRequestControl variable. It
|
|
will clear MOR_CLEAR_MEMORY_BIT bit if it is set. It will also do TPer Reset for
|
|
those encrypted drives through EFI_STORAGE_SECURITY_COMMAND_PROTOCOL at EndOfDxe.
|
|
|
|
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "TcgMor.h"
|
|
|
|
UINT8 mMorControl;
|
|
|
|
/**
|
|
Ready to Boot Event notification handler.
|
|
|
|
@param[in] Event Event whose notification function is being invoked
|
|
@param[in] Context Pointer to the notification function's context
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
OnReadyToBoot (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN DataSize;
|
|
|
|
if (MOR_CLEAR_MEMORY_VALUE (mMorControl) == 0x0) {
|
|
//
|
|
// MorControl is expected, directly return to avoid unnecessary variable operation
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Clear MOR_CLEAR_MEMORY_BIT
|
|
//
|
|
DEBUG ((DEBUG_INFO, "TcgMor: Clear MorClearMemory bit\n"));
|
|
mMorControl &= 0xFE;
|
|
|
|
DataSize = sizeof (mMorControl);
|
|
Status = gRT->SetVariable (
|
|
MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
|
|
&gEfiMemoryOverwriteControlDataGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
DataSize,
|
|
&mMorControl
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "TcgMor: Clear MOR_CLEAR_MEMORY_BIT failure, Status = %r\n", Status));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Send TPer Reset command to reset eDrive to lock all protected bands.
|
|
Typically, there are 2 mechanism for resetting eDrive. They are:
|
|
1. TPer Reset through IEEE 1667 protocol.
|
|
2. TPer Reset through native TCG protocol.
|
|
This routine will detect what protocol the attached eDrive conform to, TCG or
|
|
IEEE 1667 protocol. Then send out TPer Reset command separately.
|
|
|
|
@param[in] Ssp The pointer to EFI_STORAGE_SECURITY_COMMAND_PROTOCOL instance.
|
|
@param[in] MediaId ID of the medium to receive data from or send data to.
|
|
|
|
**/
|
|
VOID
|
|
InitiateTPerReset (
|
|
IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Ssp,
|
|
IN UINT32 MediaId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer;
|
|
UINTN XferSize;
|
|
UINTN Len;
|
|
UINTN Index;
|
|
BOOLEAN TcgFlag;
|
|
BOOLEAN IeeeFlag;
|
|
SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA *Data;
|
|
|
|
Buffer = NULL;
|
|
TcgFlag = FALSE;
|
|
IeeeFlag = FALSE;
|
|
|
|
//
|
|
// ATA8-ACS 7.57.6.1 indicates the Transfer Length field requirements a multiple of 512.
|
|
// If the length of the TRUSTED RECEIVE parameter data is greater than the Transfer Length,
|
|
// then the device shall return the TRUSTED RECEIVE parameter data truncated to the requested Transfer Length.
|
|
//
|
|
Len = ROUNDUP512 (sizeof (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA));
|
|
Buffer = AllocateZeroPool (Len);
|
|
|
|
if (Buffer == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// When the Security Protocol field is set to 00h, and SP Specific is set to 0000h in a TRUSTED RECEIVE
|
|
// command, the device basic information data shall be returned.
|
|
//
|
|
Status = Ssp->ReceiveData (
|
|
Ssp,
|
|
MediaId,
|
|
100000000, // Timeout 10-sec
|
|
0, // SecurityProtocol
|
|
0, // SecurityProtocolSpecificData
|
|
Len, // PayloadBufferSize,
|
|
Buffer, // PayloadBuffer
|
|
&XferSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// In returned data, the ListLength field indicates the total length, in bytes,
|
|
// of the supported security protocol list.
|
|
//
|
|
Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA *)Buffer;
|
|
Len = ROUNDUP512 (
|
|
sizeof (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA) +
|
|
(Data->SupportedSecurityListLength[0] << 8) +
|
|
(Data->SupportedSecurityListLength[1])
|
|
);
|
|
|
|
//
|
|
// Free original buffer and allocate new buffer.
|
|
//
|
|
FreePool (Buffer);
|
|
Buffer = AllocateZeroPool (Len);
|
|
if (Buffer == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read full supported security protocol list from device.
|
|
//
|
|
Status = Ssp->ReceiveData (
|
|
Ssp,
|
|
MediaId,
|
|
100000000, // Timeout 10-sec
|
|
0, // SecurityProtocol
|
|
0, // SecurityProtocolSpecificData
|
|
Len, // PayloadBufferSize,
|
|
Buffer, // PayloadBuffer
|
|
&XferSize
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA *)Buffer;
|
|
Len = (Data->SupportedSecurityListLength[0] << 8) + Data->SupportedSecurityListLength[1];
|
|
|
|
//
|
|
// Iterate full supported security protocol list to check if TCG or IEEE 1667 protocol
|
|
// is supported.
|
|
//
|
|
for (Index = 0; Index < Len; Index++) {
|
|
if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_TCG) {
|
|
//
|
|
// Found a TCG device.
|
|
//
|
|
TcgFlag = TRUE;
|
|
DEBUG ((DEBUG_INFO, "This device is a TCG protocol device\n"));
|
|
break;
|
|
}
|
|
|
|
if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_IEEE1667) {
|
|
//
|
|
// Found a IEEE 1667 device.
|
|
//
|
|
IeeeFlag = TRUE;
|
|
DEBUG ((DEBUG_INFO, "This device is a IEEE 1667 protocol device\n"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!TcgFlag && !IeeeFlag) {
|
|
DEBUG ((DEBUG_INFO, "Neither a TCG nor IEEE 1667 protocol device is found\n"));
|
|
goto Exit;
|
|
}
|
|
|
|
if (TcgFlag) {
|
|
//
|
|
// As long as TCG protocol is supported, send out a TPer Reset
|
|
// TCG command to the device via the TrustedSend command with a non-zero Transfer Length.
|
|
//
|
|
Status = Ssp->SendData (
|
|
Ssp,
|
|
MediaId,
|
|
100000000, // Timeout 10-sec
|
|
SECURITY_PROTOCOL_TCG, // SecurityProtocol
|
|
0x0400, // SecurityProtocolSpecificData
|
|
512, // PayloadBufferSize,
|
|
Buffer // PayloadBuffer
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Send TPer Reset Command Successfully !\n"));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "Send TPer Reset Command Fail !\n"));
|
|
}
|
|
}
|
|
|
|
if (IeeeFlag) {
|
|
//
|
|
// TBD : Perform a TPer Reset via IEEE 1667 Protocol
|
|
//
|
|
DEBUG ((DEBUG_INFO, "IEEE 1667 Protocol didn't support yet!\n"));
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (Buffer != NULL) {
|
|
FreePool (Buffer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Notification function of END_OF_DXE.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
TPerResetAtEndOfDxe (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Ssp;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN Index;
|
|
|
|
//
|
|
// Locate all SSP protocol instances.
|
|
//
|
|
HandleCount = 0;
|
|
HandleBuffer = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiStorageSecurityCommandProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
|
|
if (EFI_ERROR (Status) || (HandleCount == 0) || (HandleBuffer == NULL)) {
|
|
return;
|
|
}
|
|
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
//
|
|
// Get the SSP interface.
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiStorageSecurityCommandProtocolGuid,
|
|
(VOID **)&Ssp
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **)&BlockIo
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
InitiateTPerReset (Ssp, BlockIo->Media->MediaId);
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
}
|
|
|
|
/**
|
|
Entry Point for TCG MOR Control driver.
|
|
|
|
@param[in] ImageHandle Image handle of this driver.
|
|
@param[in] SystemTable A Pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS
|
|
@return Others Some error occurs.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MorDriverEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN DataSize;
|
|
EFI_EVENT Event;
|
|
|
|
///
|
|
/// The firmware is required to create the MemoryOverwriteRequestControl UEFI variable.
|
|
///
|
|
|
|
DataSize = sizeof (mMorControl);
|
|
Status = gRT->GetVariable (
|
|
MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
|
|
&gEfiMemoryOverwriteControlDataGuid,
|
|
NULL,
|
|
&DataSize,
|
|
&mMorControl
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Set default value to 0
|
|
//
|
|
mMorControl = 0;
|
|
Status = gRT->SetVariable (
|
|
MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
|
|
&gEfiMemoryOverwriteControlDataGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
DataSize,
|
|
&mMorControl
|
|
);
|
|
DEBUG ((DEBUG_INFO, "TcgMor: Create MOR variable! Status = %r\n", Status));
|
|
} else {
|
|
//
|
|
// Create a Ready To Boot Event and Clear the MorControl bit in the call back function.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "TcgMor: Create ReadyToBoot Event for MorControl Bit cleaning!\n"));
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_CALLBACK,
|
|
OnReadyToBoot,
|
|
NULL,
|
|
&Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "TcgMor: Create EndofDxe Event for Mor TPer Reset!\n"));
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
TPerResetAtEndOfDxe,
|
|
NULL,
|
|
&gEfiEndOfDxeEventGroupGuid,
|
|
&Event
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|