alder_lake_bios/Oem/L05/FeatureCommon/InsydeL05ModulePkg/Computrace/EraseCptSmm/EraseCptSmm.c

449 lines
13 KiB
C

/** @file
SMM Interface for the EraseCpt Tool
;******************************************************************************
;* Copyright (c) 2019, Insyde Software Corporation. 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 Corporation.
;*
;******************************************************************************
*/
#include "EraseCptSmm.h"
EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL;
/**
Read information from the CPU save state.
@param Register Specifies the CPU register to read form the save state.
@param Width The number of bytes to read from the CPU save state.
@param CpuNum Specifies the zero-based index of the CPU save state.
@param RegisterData Upon return, this holds the CPU register value read from the save state.
@retval EFI_SUCCESS The register was read from Save State
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
@retval EFI_INVALID_PARAMTER This or Buffer is NULL.
**/
EFI_STATUS
ReadDwordRegister (
IN EFI_SMM_SAVE_STATE_REGISTER RegisterNum,
IN UINTN Width,
IN UINTN CpuNum,
OUT VOID *RegisterData
)
{
EFI_STATUS Status;
Status = mSmmCpu->ReadSaveState (
mSmmCpu,
Width,
RegisterNum,
CpuNum,
RegisterData
);
return Status;
}
/**
Write value to a CPU Save State register on the target processor.
This function abstracts the differences that whether the CPU Save State register is in the
IA32 CPU Save State Map or X64 CPU Save State Map.
This function supports writing a CPU Save State register in SMBase relocation handler.
@param RegisterNum Specifies the CPU register to write to the save state.
@param Width The number of bytes to read from the CPU save state.
@param CpuNum Specifies the zero-based index of the CPU save state.
@param RegisterData Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written to Save State.
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
@retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
**/
EFI_STATUS
WriteDwordRegister (
IN EFI_SMM_SAVE_STATE_REGISTER RegisterNum,
IN UINTN Width,
IN UINTN CpuNum,
IN VOID *RegisterData
)
{
EFI_STATUS Status;
Status = mSmmCpu->WriteSaveState (
mSmmCpu,
Width,
RegisterNum,
CpuNum,
RegisterData
);
return Status;
}
/**
Set Erase Flag.
@param None
@retval L05_COMPUTRACE_SET_ERASE_FLAG_SUCCESS Function successful.
@retval L05_COMPUTRACE_SET_ERASE_FLAG_FAILED Function failed.
**/
UINT32
SetEraseFlag (
VOID
)
{
EFI_STATUS Status;
#ifdef L05_SPECIFIC_VARIABLE_SERVICE_ENABLE
EFI_L05_VARIABLE_PROTOCOL *L05VariablePtr;
UINT32 DataLength;
UINT8 ComputraceEraseFlag;
#else
EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *SmmFwBlockService;
UINT8 *EepromBuffer;
EFI_L05_EEPROM_MAP_120 *EepromPtr;
UINTN EepromBase;
UINTN EepromSize;
#endif
Status = EFI_SUCCESS;
#ifdef L05_SPECIFIC_VARIABLE_SERVICE_ENABLE
L05VariablePtr = NULL;
Status = gSmst->SmmLocateProtocol (&gEfiL05VariableProtocolGuid, NULL, &L05VariablePtr);
if (EFI_ERROR (Status)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
ComputraceEraseFlag = 0;
DataLength = sizeof (ComputraceEraseFlag);
//
// Get Erase Flag
//
Status = L05VariablePtr->GetVariable (
L05VariablePtr,
&gL05ComputraceEraseFlagGuid,
&DataLength,
&ComputraceEraseFlag
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
if (!EFI_ERROR (Status) && (ComputraceEraseFlag == L05_ERASE_FLAG_ENABLE)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_SUCCESS;
}
//
// Set Erase Flag
//
ComputraceEraseFlag = L05_ERASE_FLAG_ENABLE;
DataLength = sizeof (ComputraceEraseFlag);
Status = L05VariablePtr->SetVariable (
L05VariablePtr,
&gL05ComputraceEraseFlagGuid,
DataLength,
&ComputraceEraseFlag
);
if (EFI_ERROR (Status)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
#else
SmmFwBlockService = NULL;
EepromBase = 0;
EepromSize = 0;
Status = gSmst->SmmLocateProtocol (&gEfiSmmFwBlockServiceProtocolGuid, NULL, &SmmFwBlockService);
if (EFI_ERROR (Status)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
EepromBase = (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionEepromGuid, 1);
EepromSize = (UINTN) FdmGetNAtSize (&gL05H2OFlashMapRegionEepromGuid, 1);
if ((EepromBase == 0) || (EepromSize == 0)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
//
// Get EEPROM data
//
EepromBuffer = AllocatePages (EFI_SIZE_TO_PAGES (EepromSize));
if (EepromBuffer == NULL) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
ZeroMem (EepromBuffer, (EFI_SIZE_TO_PAGES (EepromSize) * EFI_PAGE_SIZE));
CopyMem ((VOID *) EepromBuffer, (VOID *) EepromBase, EepromSize);
EepromPtr = (EFI_L05_EEPROM_MAP_120 *) EepromBuffer;
if (EepromPtr->ComputraceEraseFlag[0] == L05_ERASE_FLAG_ENABLE) {
return L05_COMPUTRACE_SET_ERASE_FLAG_SUCCESS;
}
Status = SmmFwBlockService->EraseBlocks (SmmFwBlockService, EepromBase, &EepromSize);
if (EFI_ERROR (Status)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
//
// Set Erase Flag
//
EepromPtr->ComputraceEraseFlag[0] = L05_ERASE_FLAG_ENABLE;
Status = SmmFwBlockService->Write (SmmFwBlockService, EepromBase, &EepromSize, (VOID *) EepromBuffer);
FreePages (EepromBuffer, EFI_SIZE_TO_PAGES (EepromSize));
if (EFI_ERROR (Status)) {
return L05_COMPUTRACE_SET_ERASE_FLAG_FAILED;
}
#endif
return L05_COMPUTRACE_SET_ERASE_FLAG_SUCCESS;
}
/**
Check Erase Flag.
@param None
@retval L05_COMPUTRACE_CHECK_ERASE_FLAG_SUCCESS Flag set.
@retval L05_COMPUTRACE_CHECK_ERASE_FLAG_NOT_SET Flag not set.
**/
UINT32
CheckEraseFlag (
VOID
)
{
#ifdef L05_SPECIFIC_VARIABLE_SERVICE_ENABLE
EFI_STATUS Status;
EFI_L05_VARIABLE_PROTOCOL *L05VariablePtr;
UINT32 DataLength;
UINT8 ComputraceEraseFlag;
#else
UINTN EepromBase;
#endif
#ifdef L05_SPECIFIC_VARIABLE_SERVICE_ENABLE
Status = EFI_SUCCESS;
L05VariablePtr = NULL;
Status = gSmst->SmmLocateProtocol (&gEfiL05VariableProtocolGuid, NULL, &L05VariablePtr);
if (EFI_ERROR (Status)) {
return L05_COMPUTRACE_CHECK_ERASE_FLAG_NOT_SET;
}
ComputraceEraseFlag = 0;
DataLength = sizeof (ComputraceEraseFlag);
//
// Get Erase Flag
//
Status = L05VariablePtr->GetVariable (
L05VariablePtr,
&gL05ComputraceEraseFlagGuid,
&DataLength,
&ComputraceEraseFlag
);
if (EFI_ERROR (Status)) {
return L05_COMPUTRACE_CHECK_ERASE_FLAG_NOT_SET;
}
//
// Check Erase Flag
//
return (ComputraceEraseFlag == L05_ERASE_FLAG_ENABLE) ? L05_COMPUTRACE_CHECK_ERASE_FLAG_SUCCESS : L05_COMPUTRACE_CHECK_ERASE_FLAG_NOT_SET;
#else
EepromBase = (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionEepromGuid, 1);
if (EepromBase == 0) {
return L05_COMPUTRACE_CHECK_ERASE_FLAG_NOT_SET;
}
//
// Check Erase Flag
//
if (((EFI_L05_EEPROM_MAP_120 *) EepromBase)->ComputraceEraseFlag[0] != L05_ERASE_FLAG_ENABLE) {
return L05_COMPUTRACE_CHECK_ERASE_FLAG_NOT_SET;
}
return L05_COMPUTRACE_CHECK_ERASE_FLAG_SUCCESS;
#endif
}
/**
Check Erase Result.
@param None
@retval L05_COMPUTRACE_CHECK_ERASE_RESULT_SUCCESS Erased.
@retval L05_COMPUTRACE_CHECK_ERASE_RESULT_NOT_ERASED Not Erased.
**/
UINT32
CheckEraseResult (
VOID
)
{
UINTN ComputraceFvBase;
EFI_FIRMWARE_VOLUME_HEADER *Fvh;
ComputraceFvBase = (UINTN) FdmGetAddressById (&gH2OFlashMapRegionFvGuid, &gL05H2OFlashMapRegionComputraceFvGuid, 1);
Fvh = NULL;
if (ComputraceFvBase == 0) {
return L05_COMPUTRACE_CHECK_ERASE_RESULT_NOT_ERASED;
}
//
// Check FV header's signature is valid or not
//
Fvh = (EFI_FIRMWARE_VOLUME_HEADER *) ComputraceFvBase;
if (Fvh->Signature == EFI_FVH_SIGNATURE) {
return L05_COMPUTRACE_CHECK_ERASE_RESULT_NOT_ERASED;
}
return L05_COMPUTRACE_CHECK_ERASE_RESULT_SUCCESS;
}
/**
Callback function for SMM EraseCpt.
@param CpuNum CPU number.
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
EFIAPI
L05SmmEraseCptCallback (
IN UINTN CpuNum
)
{
UINT32 ErrorStatus;
UINT32 Eax;
UINT32 Ebx;
ErrorStatus = L05_COMPUTRACE_ERASE_FUNCTION_UNEXPECTED_ERROR;
Eax = 0;
Ebx = 0;
//
// Check function signature is valid or not
//
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
if (Eax != L05_COMPUTRACE_ERASE_FUNCTION) {
return EFI_UNSUPPORTED;
}
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RBX, sizeof (UINT32), CpuNum, &Ebx);
switch (Ebx) {
case L05_COMPUTRACE_SET_ERASE_FLAG:
ErrorStatus = SetEraseFlag();
break;
case L05_COMPUTRACE_CHECK_ERASE_FLAG:
ErrorStatus = CheckEraseFlag();
break;
case L05_COMPUTRACE_CHECK_ERASE_RESULT:
ErrorStatus = CheckEraseResult();
break;
default:
ErrorStatus = L05_COMPUTRACE_ERASE_FUNCTION_UNEXPECTED_ERROR;
break;
}
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &ErrorStatus);
return EFI_SUCCESS;
}
/**
EraseCpt SMM entry.
According to Lenovo Notebook Remove Computrace Requirement for PRC Version 1.32 draft,
register SMI Interface for the EraseCpt Tool.
@param ImageHandle The firmware allocated handle for the UEFI image.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
L05EraseCptSmmEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
BOOLEAN ComputraceSupported;
EFI_L05_SMM_SW_SMI_INTERFACE_PROTOCOL *L05SwSmiPtr;
Status = EFI_SUCCESS;
ComputraceSupported = TRUE;
L05SwSmiPtr = NULL;
//
// Locate Smm Cpu protocol for Cpu save state manipulation
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmCpuProtocolGuid,
NULL,
&mSmmCpu
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Locate L05SwSmi protocol for register Software SMI callback function
//
Status = gSmst->SmmLocateProtocol (
&gEfiL05SmmSwSmiInterfaceProtocolGuid,
NULL,
&L05SwSmiPtr
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = L05SwSmiPtr->RegisterCallbackFunction (
L05SwSmiPtr,
L05_SECURITY_SW_SMI,
FeatureCallbackType,
L05SmmEraseCptCallback
);
if (EFI_ERROR (Status)) {
return Status;
}
return Status;
}