alder_lake_bios/Oem/L05/FeatureCommon/InsydeL05ModulePkg/Computrace/Smm/L05SmmComputrace.c

419 lines
13 KiB
C

/** @file
SPEC : Computrace implement requirement v1.2.doc
;******************************************************************************
;* Copyright (c) 2013 - 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 "L05SmmComputrace.h"
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;
}
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;
}
EFI_STATUS
UpdateL05ComputraceInfo (
IN OUT EFI_L05_COMPUTRACE_AREA *L05ComputraceArea
)
{
if ((FdmGetNAtAddr (&gL05H2OFlashMapRegionComputraceGuid, 1) == (UINTN) L05_INVALID_VALUE) ||
(FdmGetNAtSize (&gL05H2OFlashMapRegionComputraceGuid, 1) == (UINTN) L05_INVALID_VALUE)) {
return EFI_UNSUPPORTED;
}
CopyMem (L05ComputraceArea, (VOID *) (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionComputraceGuid, 1), sizeof (EFI_L05_COMPUTRACE_AREA));
return EFI_SUCCESS;
}
EFI_STATUS
SaveL05ComputraceInfo (
IN EFI_L05_COMPUTRACE_AREA *L05ComputraceArea
)
{
EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *SmmFwBlockService;
EFI_STATUS Status;
UINTN DataLength;
UINTN ComputraceRegionBase;
UINTN ComputraceRegionSize;
SmmFwBlockService = NULL;
Status = EFI_SUCCESS;
DataLength = 0;
ComputraceRegionBase = (UINTN) FdmGetNAtAddr (&gL05H2OFlashMapRegionComputraceGuid, 1);
ComputraceRegionSize = (UINTN) FdmGetNAtSize (&gL05H2OFlashMapRegionComputraceGuid, 1);
if ((ComputraceRegionBase == (UINTN) L05_INVALID_VALUE) || (ComputraceRegionSize == (UINTN) L05_INVALID_VALUE)) {
return EFI_UNSUPPORTED;
}
Status = gSmst->SmmLocateProtocol (&gEfiSmmFwBlockServiceProtocolGuid, NULL, &SmmFwBlockService);
if (EFI_ERROR (Status)) {
return Status;
}
DataLength = MIN (ComputraceRegionSize, sizeof (EFI_L05_COMPUTRACE_AREA));
Status = SmmFwBlockService->EraseBlocks (SmmFwBlockService, ComputraceRegionBase, &ComputraceRegionSize);
if (EFI_ERROR (Status)) {
return Status;
}
return SmmFwBlockService->Write (SmmFwBlockService, ComputraceRegionBase, &DataLength, (UINT8 *) L05ComputraceArea);
}
EFI_STATUS
LoadL05ComputraceInfo (
IN OUT EFI_L05_COMPUTRACE_AREA *L05ComputraceArea
)
{
EFI_STATUS Status;
UINT32 ComputraceRegionBase;
UINT32 ComputraceRegionSize;
Status = EFI_SUCCESS;
ComputraceRegionBase = (UINT32) FdmGetNAtAddr (&gL05H2OFlashMapRegionComputraceGuid, 1);
ComputraceRegionSize = (UINT32) FdmGetNAtSize (&gL05H2OFlashMapRegionComputraceGuid, 1);
if ((ComputraceRegionBase == (UINTN) L05_INVALID_VALUE) || (ComputraceRegionSize == (UINTN) L05_INVALID_VALUE)) {
return EFI_UNSUPPORTED;
}
CopyMem (L05ComputraceArea, (VOID *) (UINTN) ComputraceRegionBase, sizeof (EFI_L05_COMPUTRACE_AREA));
return Status;
}
EFI_STATUS
SetComputraceDisableKey (
IN UINT32 *EfiL05ComputraceDisableKey
)
{
EFI_STATUS Status;
EFI_L05_COMPUTRACE_AREA L05ComputraceArea;
Status = EFI_SUCCESS;
Status = LoadL05ComputraceInfo (&L05ComputraceArea);
if (EFI_ERROR (Status)) {
return Status;
}
L05ComputraceArea.DisableKey = *EfiL05ComputraceDisableKey ^ L05ComputraceArea.Mask;
return SaveL05ComputraceInfo (&L05ComputraceArea);
}
EFI_STATUS
GetComputraceDisableKey (
IN OUT UINT32 *EfiL05ComputraceDisableKey
)
{
EFI_STATUS Status;
EFI_L05_COMPUTRACE_AREA L05ComputraceArea;
Status = EFI_SUCCESS;
Status = LoadL05ComputraceInfo (&L05ComputraceArea);
if (EFI_ERROR (Status)) {
return Status;
}
*EfiL05ComputraceDisableKey = L05ComputraceArea.DisableKey ^ L05ComputraceArea.Mask;
return Status;
}
EFI_STATUS
EFIAPI
L05SmmComputraceGetSetStateCallback (
IN UINTN CpuNum
)
{
EFI_STATUS Status;
UINT32 Eax;
UINT32 Ebx;
EFI_L05_COMPUTRACE_AREA L05ComputraceArea;
UINT32 DisableKey;
UINT32 RegisterBuf;
UINT32 Index;
static UINT32 TrialCount = OEM_L05_COMPUTRACE_MAX_RETRY;
DisableKey = 0;
Index = 0;
Eax = 0;
Ebx = 0;
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
//
// Check function signature is valid or not
//
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
if ((Eax != OEM_L05_COMPUTRACE_SET_STATE_ENABLE_FUNCTION) &&
(Eax != OEM_L05_COMPUTRACE_SET_STATE_DISABLE_FUNCTION) &&
(Eax != OEM_L05_COMPUTRACE_GET_STATE_FUNCTION)) {
return EFI_UNSUPPORTED;
}
Status = UpdateL05ComputraceInfo (&L05ComputraceArea);
if (EFI_ERROR (Status)) {
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
return EFI_SUCCESS;
}
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &Eax);
switch (Eax) {
case OEM_L05_COMPUTRACE_GET_STATE_FUNCTION:
switch (L05ComputraceArea.ComputraceState) {
case EFI_L05_COMPUTRACE_ENABLING:
case EFI_L05_COMPUTRACE_ENABLED:
RegisterBuf = OEM_L05_COMPUTRACE_GET_STATE_ENABLED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
case EFI_L05_COMPUTRACE_DISABLED:
RegisterBuf = OEM_L05_COMPUTRACE_GET_STATE_DISABLED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
default:
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
break;
}
break;
case OEM_L05_COMPUTRACE_SET_STATE_ENABLE_FUNCTION:
switch (L05ComputraceArea.ComputraceState) {
case EFI_L05_COMPUTRACE_ENABLING:
case EFI_L05_COMPUTRACE_ENABLED:
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_ALREADY_ENABLED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
case EFI_L05_COMPUTRACE_DISABLED:
L05ComputraceArea.Mask = L05_COMPUTRACE_DEFAULT_MASK;
L05ComputraceArea.ComputraceState = EFI_L05_COMPUTRACE_ENABLING;
Status = SaveL05ComputraceInfo (&L05ComputraceArea);
if (EFI_ERROR (Status)) {
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
return EFI_SUCCESS;
}
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RBX, sizeof (UINT32), CpuNum, &DisableKey);
Status = SetComputraceDisableKey (&DisableKey);
if (EFI_ERROR (Status)) {
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
return EFI_SUCCESS;
}
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_SUCCESS;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
default:
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
}
break;
case OEM_L05_COMPUTRACE_SET_STATE_DISABLE_FUNCTION:
//
// By L05 spec, Disable Computrace must has trial count to prevent brute-force attack.
//
if (TrialCount == 0) {
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
return EFI_SUCCESS;
}
switch (L05ComputraceArea.ComputraceState) {
case EFI_L05_COMPUTRACE_ENABLING:
case EFI_L05_COMPUTRACE_ENABLED:
Status = GetComputraceDisableKey (&DisableKey);
if (EFI_ERROR (Status)) {
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
return EFI_SUCCESS;
}
ReadDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RBX, sizeof (UINT32), CpuNum, &Ebx);
if (DisableKey != Ebx) {
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_KEY_NOT_MATCH;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
TrialCount--;
return EFI_SUCCESS;
}
//
// Clear All Computrace Area when disabling.
//
for (Index = 0; Index < sizeof (EFI_L05_COMPUTRACE_AREA); Index++) {
((UINT8 *) &L05ComputraceArea)[Index] = 0xFF;
}
L05ComputraceArea.ComputraceState = EFI_L05_COMPUTRACE_DISABLED;
Status = SaveL05ComputraceInfo (&L05ComputraceArea);
if (EFI_ERROR (Status)) {
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
return EFI_SUCCESS;
}
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_SUCCESS;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
case EFI_L05_COMPUTRACE_DISABLED:
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_ALREADY_DISABLED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
default:
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
}
break;
default:
RegisterBuf = OEM_L05_COMPUTRACE_SET_STATE_NOT_SUPPORTED;
WriteDwordRegister (EFI_SMM_SAVE_STATE_REGISTER_RAX, sizeof (UINT32), CpuNum, &RegisterBuf);
break;
}
return EFI_SUCCESS;
}
EFI_STATUS
L05SmmComputraceEntryPoint (
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;
//
// Skip Computrace init if platform doesn't support.
//
Status = OemSvcCheckComputraceSupportStatus (&ComputraceSupported);
if (Status == EFI_MEDIA_CHANGED && !ComputraceSupported) {
return EFI_SUCCESS;
}
//
// Locate Smm Cpu protocol for Cpu save state manipulation
//
Status = gSmst->SmmLocateProtocol (
&gEfiSmmCpuProtocolGuid,
NULL,
&mSmmCpu
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Register Software SMI function with L05SwSmi Driver
//
Status = gSmst->SmmLocateProtocol (
&gEfiL05SmmSwSmiInterfaceProtocolGuid,
NULL,
&L05SwSmiPtr
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = L05SwSmiPtr->RegisterCallbackFunction (
L05SwSmiPtr,
L05_SECURITY_SW_SMI,
FeatureCallbackType,
L05SmmComputraceGetSetStateCallback
);
if (EFI_ERROR (Status)) {
return Status;
}
return Status;
}