alder_lake_bios/Intel/AlderLake/AlderLakePlatSamplePkg/Features/Rpe/RpeEraseActions.c

587 lines
18 KiB
C

/** @file
;******************************************************************************
;* Copyright 2021 Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corp.
;*
;******************************************************************************
*/
/**@file
RPE Erase Action Implementation.
@copyright
INTEL CONFIDENTIAL
Copyright 2020 - 2021 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains a 'Sample Driver' and is licensed as such under the terms
of your license agreement with Intel or your vendor. This file may be modified
by the user, subject to the additional terms of the license agreement.
@par Specification Reference:
**/
#include <Library/HobLib.h>
#include <SetupVariable.h>
#include <Protocol/AmtWrapperProtocol.h>
#include <Library/PcdLib.h>
#include <Library/DxeAsfHeciLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/AmtReadyToBoot.h>
#include <Library/SecureEraseDxeLib.h>
#include "RpeAmtSupport.h"
#include "RpeEraseActions.h"
#include <BootStateLib.h>
#include <Library/UefiLib.h>
#include <TcgSetup.h>
#include <Protocol/Tcg2Protocol.h>
#include <Library/Tpm2CommandLib.h>
#include <Library/DxeMeLib.h>
#include <Library/TimerLib.h>
//[-start-210531-IB09480142-add]//
#include <Protocol/HddPasswordService.h>
//[-end-210531-IB09480142-add]//
extern RPE_RESULT mRpeResult;
/**
This function is executed on AMT Ready to boot and performs SSD Erase.
**/
VOID
EFIAPI
RpeSsdEraseEvent (
VOID
);
//
// Setup related variables that would be cleared.
// OEMs can update this structure to define the Setup Variables to be restored to defaults during RPE BIOS Clear Action.
//
//[-start-210531-IB09480142-modify]//
USER_DATA_VARIABLE_ENTRY mUserDataVariableList[] = {
{ L"Setup" , &gSetupVariableGuid },
{ L"MeInfoSetup" , &gMeInfoSetupGuid },
{ L"MeBiosExtensionSetup", &gMeBiosExtensionSetupGuid },
{ L"TcgSetup" , &gSetupVariableGuid },
{ L"SaSetup" , &gSaSetupVariableGuid },
{ L"CpuSetup" , &gCpuSetupVariableGuid },
{ L"PchSetup" , &gPchSetupVariableGuid },
{ L"MeSetup" , &gMeSetupVariableGuid },
{ L"Setup" , &gSystemConfigurationGuid }
};
//[-end-210531-IB09480142-modify]//
GLOBAL_REMOVE_IF_UNREFERENCED AMT_READY_TO_BOOT_PROTOCOL mRpeSsdEraseReadyToBoot = {
AMT_READY_TO_BOOT_PROTOCOL_REVISION,
RpeSsdEraseEvent
};
/**
Check if user requires real mode or simulation mode erase.
**/
BOOLEAN
IsRealEraseMode (
VOID
)
{
EFI_STATUS Status;
ME_SETUP MeSetup;
UINTN VariableSize;
VariableSize = sizeof (ME_SETUP);
Status = gRT->GetVariable (
L"MeSetup",
&gMeSetupVariableGuid,
NULL,
&VariableSize,
&MeSetup
);
if (!EFI_ERROR (Status) && MeSetup.RpeSsdEraseRealMode == 1) {
return TRUE;
} else {
return FALSE;
}
}
//[-start-210531-IB09480142-add]//
VOID
EFIAPI
HddUnLockNotificationEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_HDD_PASSWORD_DIALOG_PROTOCOL *HddPasswordDialogProtocol;
Status = gBS->LocateProtocol (&gEfiHddPasswordDialogProtocolGuid, NULL, (VOID **) &HddPasswordDialogProtocol);
if (EFI_ERROR (Status)) {
return;
}
gBS->CloseEvent (Event);
HddPasswordDialogProtocol->HddPasswordUnlocked (HddPasswordDialogProtocol);
}
//[-end-210531-IB09480142-add]//
/**
Perform RPE SSD Erase Actions.
@retval EFI_SUCCESS Erase device succeed
@retval EFI_UNSUPPORTED The device is not supported
@retval EFI_ACCESS_DENIED User has entered wrong password too many times
@retval EFI_ABORTED The device is supported, but the system
has failed to erase it
**/
EFI_STATUS
RpeSsdEraseActions (
VOID
)
{
EFI_STATUS Status;
BIOS_RPE_BOOT_PARAMETERS *BiosRpeBootParameters;
CHAR8 *RpeString;
RpeString = "RPE";
// Create Empty BIOS RpeBootParameters Structure, to store BIOS RPE Variables
BiosRpeBootParameters = AllocateZeroPool (sizeof (BIOS_RPE_BOOT_PARAMETERS));
if (BiosRpeBootParameters == NULL) {
DEBUG ((DEBUG_ERROR, "RPE: BiosRpeBootParameters EFI_OUT_OF_RESOURCES.\n"));
Status = EFI_OUT_OF_RESOURCES;
} else {
// Update the BIOS RpeBootParameters Structure.
Status = RpeInitialize (BiosRpeBootParameters);
//
// Start SSD Erase Operation
//
if (!EFI_ERROR (Status)) {
Status = PerformSsdErase (REMOTE_PLATFORM_ERASE_FEATURE, IsRealEraseMode ());
DEBUG ((DEBUG_INFO, "%a: SSD Erase Status = %r\n", RpeString, Status));
}
}
if (Status == EFI_SUCCESS) {
SendRpePetAlert (ASF_RPE_EVENT_DATA3_DEVICE_ERASED_SUCCESSFULLY, ASF_RPE_EVENT_DATA4_SSD_ERASE_ACTION, ASF_RPE_EVENT_OFFSET_PROGRESS);
} else if (Status == EFI_UNSUPPORTED) {
SendRpePetAlert (ASF_RPE_EVENT_DATA3_ERASING_DEVICE_UNSUPPORTED, ASF_RPE_EVENT_DATA4_SSD_ERASE_ACTION, ASF_RPE_EVENT_OFFSET_FAILURE);
} else {
DEBUG ((DEBUG_ERROR, "RPE: SSD Erase Action - Failed. Status = %r\n", Status));
SendRpePetAlert (ASF_RPE_EVENT_DATA3_ERROR_ERASING_DEVICE, ASF_RPE_EVENT_DATA4_SSD_ERASE_ACTION, ASF_RPE_EVENT_OFFSET_FAILURE);
}
// Decrement the BitMask in BiosRpeBootParameters and update to NVRAM.
if (BiosRpeBootParameters != NULL) {
DecrementBiosRpeBootParameter (BiosRpeBootParameters, RPE_SECURE_ERASE_ALL_SSD, Status);
FreePool (BiosRpeBootParameters);
}
return Status;
}
/**
This function is executed on AMT Ready to boot and performs SSD Erase RPE Action.
**/
VOID
EFIAPI
RpeSsdEraseEvent (
VOID
)
{
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "RPE: SSD Erase :: RpeSsdEraseOnReadyToBoot\n"));
Status = RpeSsdEraseActions ();
// Other RPE-AMT related actions/handshake will be performed during the reboot.
gRT->ResetSystem (EfiResetWarm, Status, 0, NULL);
// Control should not come here.
CpuDeadLoop ();
}
/**
This event gets control if DevicePasswordSupport is enabled and ready.
It performs SSD Erase RPE Actions.
@param[in] Event The instance of EFI_EVENT.
@param[in] Context The parameter passed in.
**/
VOID
EFIAPI
RpeSsdEraseNotificationEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
VOID *Protocol;
DEBUG ((DEBUG_INFO, "RPE: SSD Erase :: SsdEraseNotificationEvent\n"));
Status = gBS->LocateProtocol (&gTrustedConsoleConnectedProtocolGuid, NULL, (VOID **) &Protocol);
if (EFI_ERROR (Status)) {
return;
}
RpeSsdEraseEvent ();
gBS->CloseEvent (Event);
}
/**
Register RPE SSD Erase Action Event
@retval EFI_SUCCESS SSD Erase procedure has been started
@retval EFI_ABORTED Failed to register Ssd Erase Event.
**/
EFI_STATUS
RegisterRpeSsdEraseEvent (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
VOID *Registration;
//[-start-210531-IB09480142-add]//
VOID *Registration2;
//[-end-210531-IB09480142-add]//
DEBUG ((DEBUG_INFO, "RPE: SSD Erase :: RegisterRpeSsdEraseEvent\n"));
//
// RPE SSD Erase is requested, so this module will take control over HDD's and OPAL's unlocking process
//
PcdSetBoolS (PcdSkipHddPasswordPrompt, TRUE);
PcdSetBoolS (PcdSkipOpalPasswordPrompt, TRUE);
//
// Register notify function when trusted console connected.
//
EfiCreateProtocolNotifyEvent (
&gTrustedConsoleConnectedProtocolGuid,
TPL_CALLBACK,
RpeSsdEraseNotificationEvent,
NULL,
&Registration
);
//[-start-210531-IB09480142-add]//
EfiCreateProtocolNotifyEvent (
&gEfiHddPasswordDialogProtocolGuid,
TPL_NOTIFY,
HddUnLockNotificationEvent,
NULL,
&Registration2
);
//[-end-210531-IB09480142-add]//
//
// Install an Amt ready to boot protocol.
//
Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&Handle,
&gAmtReadyToBootProtocolGuid,
&mRpeSsdEraseReadyToBoot,
NULL
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}
/**
Function to perform TPM clear operation.
@retval EFI_SUCCESS Operation completed successfully.
@retval EFI_TIMEOUT The register can't run into the expected status in time.
@retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
@retval EFI_DEVICE_ERROR Unexpected device behavior.
**/
EFI_STATUS
TpmClearOperation (
VOID
)
{
EFI_STATUS Status;
TPMS_AUTH_COMMAND *AuthSession;
AuthSession = NULL; // NULL indicates no platform auth change needed.
DEBUG ((DEBUG_INFO, "Tpm2ClearControl ... \n"));
Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO);
DEBUG ((DEBUG_INFO, "Tpm2ClearControl Status - %r\n", Status));
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Tpm2ClearControl Failed.\n"));
return Status;
}
DEBUG ((DEBUG_INFO, "Tpm2Clear ... \n"));
Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession);
DEBUG ((DEBUG_INFO, "Tpm2Clear Status - %r\n", Status));
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Tpm2Clear Failed.\n"));
return Status;
}
return Status;
}
/**
End of DXE CallBack event to perform TPM Clear after TCG2 protocol is installed.
@param[in] Event A pointer to the Event that triggered the callback.
@param[in] Context A pointer to private data registered with the callback function.
**/
VOID
EFIAPI
TpmClearEndOfDxeEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
BIOS_RPE_BOOT_PARAMETERS *BiosRpeBootParameters;
DEBUG ((DEBUG_INFO, "RPE: TPM Clear::TpmClearEndOfDxeEvent\n"));
if (Event != NULL) {
gBS->CloseEvent (Event);
}
// Create Empty BIOS RpeBootParameters Structure, to store BIOS RPE Variables
BiosRpeBootParameters = AllocateZeroPool (sizeof (BIOS_RPE_BOOT_PARAMETERS));
if (BiosRpeBootParameters == NULL) {
DEBUG ((DEBUG_ERROR, "RPE: TPM Clear::BiosRpeBootParameters EFI_OUT_OF_RESOURCES.\n"));
Status = EFI_OUT_OF_RESOURCES;
} else {
// Update the BIOS RpeBootParameters Structure.
Status = RpeInitialize (BiosRpeBootParameters);
if (!EFI_ERROR (Status)) {
//
// Start TPM Clear Operation
//
Status = TpmClearOperation ();
DEBUG ((DEBUG_INFO, "RPE: TPM Clear::TPM Clear Status = %r\n", Status));
}
}
if (Status == EFI_SUCCESS) {
SendRpePetAlert (ASF_RPE_EVENT_DATA3_DEVICE_ERASED_SUCCESSFULLY, ASF_RPE_EVENT_DATA4_TPM_ERASE_ACTION, ASF_RPE_EVENT_OFFSET_PROGRESS);
} else if (Status == EFI_UNSUPPORTED) {
SendRpePetAlert (ASF_RPE_EVENT_DATA3_ERASING_DEVICE_UNSUPPORTED, ASF_RPE_EVENT_DATA4_TPM_ERASE_ACTION, ASF_RPE_EVENT_OFFSET_FAILURE);
} else {
SendRpePetAlert (ASF_RPE_EVENT_DATA3_ERROR_ERASING_DEVICE, ASF_RPE_EVENT_DATA4_TPM_ERASE_ACTION, ASF_RPE_EVENT_OFFSET_FAILURE);
}
// Decrement the TPM Clear Action BitMask in BiosRpeBootParameters and update to NVRAM.
if (BiosRpeBootParameters != NULL) {
DecrementBiosRpeBootParameter (BiosRpeBootParameters, RPE_TPM_CLEAR, Status);
FreePool (BiosRpeBootParameters);
}
// Other RPE related actions/handshake will be performed during the reboot.
gRT->ResetSystem (EfiResetWarm, Status, 0, NULL);
// Control should not come here.
CpuDeadLoop ();
}
/**
Function to trigger TPM Clear operation by invoking Tpm2ClearControl and Tpm2Clear.
If TPM is present/enabled and TCG2 protocol is not installed while this driver is getting executed,
then an End of DXE event will be registered and operation will be performed later in the boot flow.
TPM Clear affects Endorsement keys, NV Indexes and objects stored in the TPM's Owner or
Endorsement hierarchies (like bitlocker key / virtual smart card / fingerprint data etc...)
TPM clear does not affect TPM measurements.
@retval EFI_SUCCESS Operation completed successfully.
@retval EFI_UNSUPPORTED If TPM is not present/enabled.
@retval EFI_DEVICE_ERROR If TPM is present/enabled and TCG2 protocol is not installed.
@retval EFI_TIMEOUT The register can't run into the expected status in time.
@retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
@retval EFI_DEVICE_ERROR Unexpected device behavior.
**/
EFI_STATUS
TriggerTpmClear (
VOID
)
{
EFI_STATUS Status;
EFI_EVENT Event;
EFI_TCG2_PROTOCOL *Tcg2;
TCG_SETUP TcgSetup;
UINTN DataSize;
// Check TPM is present/enabled from TPM setup
DataSize = sizeof (TCG_SETUP);
Status = gRT->GetVariable (
TCG_SETUP_NAME,
&gSetupVariableGuid,
NULL,
&DataSize,
&TcgSetup
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "RPE: Unable to get TCG setup options\n", Status));
return EFI_UNSUPPORTED;
}
if ((TcgSetup.dTpm20Present == 0) && (TcgSetup.dTpm12Present == 0) && (TcgSetup.PttPresent == 0)) {
DEBUG ((DEBUG_INFO, "RPE: TPM is not present\n", Status));
return EFI_UNSUPPORTED;
}
// Locate gEfiTcg2ProtocolGuid. If installed then continue to perform TPM Clear.
// If not not installed then register an End of Dxe event to perform TPM clear and return Not Ready.
Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "RPE: Tcg2 Protocol Status - %r\n", Status));
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
TpmClearEndOfDxeEvent,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&Event
);
ASSERT_EFI_ERROR (Status);
return EFI_NOT_READY;
}
DEBUG ((DEBUG_INFO, "RPE: TCG2 Protocol Located. TPM Clear operation will be executed.\n", Status));
Status = TpmClearOperation ();
return Status;
}
/**
Delete SETUP related Variables
@retval EFI_SUCCESS. Operation is successful.
@retval EFI_ABORTED Failed to Delete Setup user data
**/
EFI_STATUS
DeleteSetupVariables (
VOID
)
{
EFI_STATUS Status;
UINTN Index;
DEBUG ((DEBUG_INFO, "Delete Setup User Data\n"));
for (Index = 0; Index < sizeof (mUserDataVariableList) / sizeof (mUserDataVariableList[0]); Index++) {
Status = gRT->SetVariable (
mUserDataVariableList[Index].Name,
mUserDataVariableList[Index].Guid,
0,
0,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "Failed to delete variable %s (%r)\n", mUserDataVariableList[Index].Name, mUserDataVariableList[Index].Guid));
if (Status != EFI_NOT_FOUND) {
return EFI_ABORTED;
}
}
}
return EFI_SUCCESS;
}
/**
Reload BIOS NVRAM Variables with its Default Configuration.
@retval EFI_SUCCESS BIOS NV Data Reload status.
@retval EFI_ABORTED Failed to Reload BIOS NV Data.
**/
EFI_STATUS
SetBiosNvDataDefaultConfig (
VOID
)
{
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "RPE: Reload BIOS Config :: SetBiosNvDataDefaultConfig\n"));
//
// Delete the NvData Variables specified in the mUserDataVariableList.
// These variables get restored with the default values in the next boot.
//
Status = DeleteSetupVariables ();
//
// Enforce booting with full configuration after Erase operations
//
UnsetBootState ();
return Status;
}
/**
Perform Unconfigure CSME without password and try to wait for completion.
@retval EFI_ABORTED Unconfiguration error
@retval EFI_TIMEOUT Unconfiguration is still in progress after time elapsed
@retval EFI_SUCCESS Unconfiguration finished successfully
**/
EFI_STATUS
RpeCsmeUnconfigure (
VOID
)
{
UINT8 UnconfigStatus;
UINT32 Timeout = UNCONFIGURE_TIMEOUT; // Timeout is set to 60 seconds
EFI_STATUS Status;
Status = HeciUnconfigWithouPwd ();
if (EFI_ERROR (Status)) {
mRpeResult = RpeCsmeUnconfigFail;
return Status;
}
do {
Status = HeciGetUnconfigureStatus (&UnconfigStatus);
if (EFI_ERROR (Status)) {
mRpeResult = RpeCsmeUnconfigFail;
return Status;
}
if (UnconfigStatus == ME_UNCONFIG_ERROR) {
mRpeResult = RpeCsmeUnconfigFail;
return EFI_ABORTED;
} else if ((UnconfigStatus == ME_UNCONFIG_NOT_IN_PROGRESS) || (UnconfigStatus == ME_UNCONFIG_FINISHED)) {
return EFI_SUCCESS;
}
MicroSecondDelay (1000000);
} while (Timeout--);
return EFI_TIMEOUT;
}