449 lines
13 KiB
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;
|
|
}
|