alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/IhisiSmm/IhisiSmm.c

444 lines
14 KiB
C

/** @file
This driver provides IHISI interface in SMM mode
;******************************************************************************
;* Copyright (c) 2018 - 2022, 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 "IhisiSmm.h"
#include <Library/BaseMemoryLib.h>
H2O_IHISI_PROTOCOL *mH2OIhisi = NULL;
EFI_SMM_FW_BLOCK_SERVICE_PROTOCOL *mSmmFwBlockService = NULL;
STATIC CONST BOOLEAN mPcdIhisiRegisterTableValid = (BOOLEAN)(FixedPcdGetPtrSize (PcdIhisiRegisterTable) % sizeof (PCD_IHISI_REGISTER_TABLE) == 0);
/**
Get Bootguard svn info from CSME
@param[out] RevocationFromMe Pointer to Arb SVN info data
@retval EFI_SUCCESS Function succeeded.
@return Other Error occurred in this function.
**/
EFI_STATUS
GetArbSvnSaveInfoFromME (
REVOCATION_VALUE *RevocationFromMe
)
{
EFI_STATUS Status;
UINT32 MeStatus;
ARB_SVN_INFO_ENTRY *ArbSvnInfo;
UINT32 NumOfEntries;
UINT8 KmId;
UINT32 Index;
BOOT_GUARD_BOOT_STATE BtgStatus;
MeStatus = ME_NOT_READY;
BtgStatus = BootGuardBootStateLegacyBoot;
ArbSvnInfo = NULL;
NumOfEntries = 1;
KmId = 0;
Status = BootGuardPlatformLibGetMeStatus (&MeStatus);
if (!EFI_ERROR (Status)) {
if (((MeStatus & 0x0f) == ME_READY)){
BtgStatus = BootGuardPlatformLibDetermineBootState ();
RevocationFromMe->BootGuardStatus = BtgStatus;
if (BtgStatus != BootGuardBootStateLegacyBoot) {
Status = gSmst->SmmAllocatePool (
EfiRuntimeServicesData,
(NumOfEntries * sizeof (ARB_SVN_INFO_ENTRY)),
(VOID**)&ArbSvnInfo
);
if (!EFI_ERROR(Status) && ArbSvnInfo != NULL) {
ArbSvnInfo = ZeroMem (ArbSvnInfo, (NumOfEntries * sizeof (ARB_SVN_INFO_ENTRY)));
//
// Get the current SVN value of ACM, BPM and KM through HECI command.
//
Status = HeciArbSvnGetInfoMsg (&NumOfEntries, ArbSvnInfo);
if (EFI_ERROR (Status) && (Status == EFI_BUFFER_TOO_SMALL)) {
Status = gSmst->SmmFreePool (ArbSvnInfo);
ASSERT_EFI_ERROR (Status);
Status = gSmst->SmmAllocatePool (
EfiRuntimeServicesData,
(NumOfEntries * sizeof (ARB_SVN_INFO_ENTRY)),
(VOID**)&ArbSvnInfo
);
if (!EFI_ERROR(Status) && ArbSvnInfo != NULL) {
//
// Get the current SVN value of ACM, BPM and KM through HECI command.
//
Status = HeciArbSvnGetInfoMsg (&NumOfEntries, ArbSvnInfo);
}
}
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to get ArbSvnInfo through HECI command, Status = %r\n", Status));
goto ArbExit;
}
} else {
DEBUG ((DEBUG_ERROR, "Failed to get ArbSvnInfo, error in Allocate Pool\n"));
Status = EFI_UNSUPPORTED;
goto ArbExit;
}
//
// Get current KMID through HECI command.
//
Status = BootGuardPlatformLibGetKMID (&KmId);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to get KMID through HECI command, Status = %r\n", Status));
goto ArbExit;
}
} else {
DEBUG ((DEBUG_ERROR, "NOT Bootguard\n"));
//BtgStatus = BootGuardBootStateLegacyBoot
RevocationFromMe->ACMSVN = 0;
RevocationFromMe->BPMSVN = 0;
RevocationFromMe->KMSVN = 0;
RevocationFromMe->KMID = 0;
Status = EFI_SUCCESS;
goto ArbExit;
}
} else {
DEBUG ((DEBUG_ERROR, "ME NOT READY\n"));
Status = EFI_UNSUPPORTED;
goto ArbExit;
}
} else {
DEBUG ((DEBUG_ERROR, "Get ME Status fail\n"));
goto ArbExit;
}
for (Index = 0; Index < NumOfEntries; Index++) {
if (ArbSvnInfo[Index].UsageId == MFT_KEY_USAGE_INDEX_OEM_ACM_MANIFEST) {
RevocationFromMe->ACMSVN = ArbSvnInfo[Index].ExecutingSvn;
}
if (ArbSvnInfo[Index].UsageId == MFT_KEY_USAGE_INDEX_BOOT_POLICY_MANIFEST) {
RevocationFromMe->BPMSVN = ArbSvnInfo[Index].ExecutingSvn;
}
if (ArbSvnInfo[Index].UsageId == MFT_KEY_USAGE_INDEX_OEM_BTG_KEY_MANIFEST) {
RevocationFromMe->KMSVN = ArbSvnInfo[Index].ExecutingSvn;
}
}
RevocationFromMe->KMID = KmId;
ArbExit:
if (ArbSvnInfo != NULL) {
Status = gSmst->SmmFreePool (ArbSvnInfo);
ASSERT_EFI_ERROR (Status);
ArbSvnInfo = NULL;
}
return Status;
}
/**
Get Bootguard svn info from Variable
@param[out] Revocation Pointer to Arb SVN info data
@retval EFI_SUCCESS Function succeeded.
@return Other Get variable fail.
**/
EFI_STATUS
GetArbSvnSaveInfoFromVariable (
REVOCATION_VALUE *Revocation
)
{
EFI_STATUS Status;
UINTN Size;
Size = sizeof (REVOCATION_VALUE);
Status = CommonGetVariable (
L"ArbSvnInfo",
&gArbSvnInfoGuid,
&Size,
Revocation
);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_ERROR, "Failed to get ArbSvnInfo variable, Status = %r\n", Status));
}
return Status;
}
/**
Ihisi function to initialize all of Bootguard SVN relative information
*/
STATIC
VOID
ArbSvnSaveInfo (
)
{
EFI_STATUS Status;
REVOCATION_VALUE RevocationCurrent;
BOOLEAN GetFromMe;
REVOCATION_VALUE Revocation;
BOOLEAN GetFromVariable;
EFI_BOOT_MODE BootMode;
BOOLEAN UpdateInfo;
GetFromMe = FALSE;
GetFromVariable = FALSE;
UpdateInfo = FALSE;
Revocation.ACMSVN = 0;
Revocation.BPMSVN = 0;
Revocation.KMSVN = 0;
Revocation.KMID = 0;
Revocation.BootGuardStatus = BootGuardBootStateLegacyBoot;
//
// Try to get the Revocation value from ME
//
Status = GetArbSvnSaveInfoFromME (&RevocationCurrent);
if (!EFI_ERROR(Status)) {
GetFromMe = TRUE;
Revocation.ACMSVN = RevocationCurrent.ACMSVN;
Revocation.BPMSVN = RevocationCurrent.BPMSVN;
Revocation.KMSVN = RevocationCurrent.KMSVN;
Revocation.KMID = RevocationCurrent.KMID;
Revocation.BootGuardStatus = RevocationCurrent.BootGuardStatus;
}
BootMode = GetBootModeHob ();
//
// The content of NV storage for variable is not reliable in recovery boot mode.
//
if (BootMode != BOOT_IN_RECOVERY_MODE) {
//
// Try to get the Revocation value from ME
//
Status = GetArbSvnSaveInfoFromVariable (&Revocation);
if (!EFI_ERROR(Status)) {
GetFromVariable = TRUE;
}
if (GetFromMe == TRUE) {
if (GetFromVariable == FALSE) {
//
// Prepare the Variable data
//
Revocation.ACMSVN = RevocationCurrent.ACMSVN;
Revocation.BPMSVN = RevocationCurrent.BPMSVN;
Revocation.KMSVN = RevocationCurrent.KMSVN;
Revocation.KMID = RevocationCurrent.KMID;
Revocation.BootGuardStatus = RevocationCurrent.BootGuardStatus;
UpdateInfo = TRUE;
} else {
//
// Update variable if necessary
//
if (Revocation.ACMSVN < RevocationCurrent.ACMSVN) {
Revocation.ACMSVN = RevocationCurrent.ACMSVN;
UpdateInfo = TRUE;
}
if (Revocation.BPMSVN < RevocationCurrent.BPMSVN) {
Revocation.BPMSVN = RevocationCurrent.BPMSVN;
UpdateInfo = TRUE;
}
if (Revocation.KMSVN < RevocationCurrent.KMSVN) {
Revocation.KMSVN = RevocationCurrent.KMSVN;
UpdateInfo = TRUE;
}
if (Revocation.KMID < RevocationCurrent.KMID) {
Revocation.KMID = RevocationCurrent.KMID;
UpdateInfo = TRUE;
}
if (Revocation.BootGuardStatus != RevocationCurrent.BootGuardStatus) {
Revocation.BootGuardStatus = RevocationCurrent.BootGuardStatus;
UpdateInfo = TRUE;
}
}
}
if (UpdateInfo == TRUE){
//
// Save related SVN values into variable, so we can get these values in PEI or SMM.
//
Status = SetVariableToSensitiveVariable (
L"ArbSvnInfo",
&gArbSvnInfoGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
sizeof (Revocation),
&Revocation
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to set ArbSvnInfo variable, Status = %r\n", Status));
}
}
}
if ((GetFromMe == TRUE) || (GetFromVariable == TRUE)) {
//
// Save BootMode Info to LockBox, so we can restore these values in SMM.
//
Status = SaveLockBox (&gArbSvnInfoGuid, &Revocation, sizeof (Revocation));
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "SaveLockBox BootMode %r\n", Status));
}
}
}
/**
Ihisi driver entry point to initialize all of IHISI relative services
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The operation completed successfully.
@retval Others An unexpected error occurred.
*/
EFI_STATUS
EFIAPI
IhisiEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Prepare Bootguard Arb Svn info for BIOS update
//
ArbSvnSaveInfo ();
Status = gSmst->SmmLocateProtocol (
&gH2OIhisiProtocolGuid,
NULL,
(VOID **) &mH2OIhisi
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
}
if (mSmmFwBlockService == NULL) {
Status = gSmst->SmmLocateProtocol (
&gEfiSmmFwBlockServiceProtocolGuid,
NULL,
(VOID **) &mSmmFwBlockService
);
if (EFI_ERROR (Status)) {
return Status;
}
}
if (FeaturePcdGet (PcdH2OIhisiFbtsSupported)) {
Status = FbtsInit ();
if (EFI_ERROR (Status)) {
return Status;
}
}
if (FeaturePcdGet (PcdH2OIhisiFbts2Supported)) {
Status = Fbts2Init ();
if (EFI_ERROR (Status)) {
return Status;
}
}
Status = BiosGCIInit ();
if (EFI_ERROR (Status)) {
return Status;
}
//
// Due to OEM can register their own IHISI command by locate H2OIhisi protocol,
// Remove this OEM service.
//
// IhisiOemHook = IhisiChipsetHook;
//
// SEG Feature - Remove H2OUVE relevant source codes
//
// Status = H2oUveSmiServiceInit ();
// if (EFI_ERROR (Status)) {
// return Status;
// }
return EFI_SUCCESS;
}
/**
Register IHISI sub function if SubFuncTable CmdNumber/AsciiFuncGuid define in PcdIhisiRegisterTable list.
@param[out] SubFuncTable Pointer to ihisi register table.
@param[out] TableCount SubFuncTable count
@retval EFI_SUCCESS Function succeeded.
@return Other Error occurred in this function.
**/
EFI_STATUS
RegisterIhisiSubFunction (
IHISI_REGISTER_TABLE *SubFuncTable,
UINT16 TableCount
)
{
EFI_STATUS Status;
UINT8 *PcdTable;
UINT8 PcdPriority;
UINT8 EndChar;
UINTN Index;
UINTN PcdCount;
UINTN PcdMaxCount;
UINTN SignatureSize;
BOOLEAN PcdFoundRegistered;
Status = EFI_SUCCESS;
EndChar = 0;
PcdFoundRegistered = FALSE;
PcdTable = (UINT8 *)PcdGetPtr (PcdIhisiRegisterTable);
PcdMaxCount = FixedPcdGetPtrSize (PcdIhisiRegisterTable) / sizeof (UINT8);
if (!mPcdIhisiRegisterTableValid) {
DEBUG ((DEBUG_ERROR, "PcdIhisiRegisterTable of description not follow PCD_IHISI_REGISTER_TABLE definition, \
it may cause some of IHISI function register fail \n"));
}
for (Index = 0; Index < TableCount; Index ++) {
PcdCount = 0;
PcdPriority = 0x80;
PcdFoundRegistered = FALSE;
SignatureSize = AsciiStrLen (SubFuncTable[Index].FuncSignature);
//
// Caculate PCD of address to find 1. CmdNumber 2. FuncSignature 3. Priority
//
do {
if (SubFuncTable[Index].CmdNumber == *(PcdTable + PcdCount)) {
PcdCount++;
if (AsciiStrnCmp (SubFuncTable[Index].FuncSignature, (CHAR8 *) (PcdTable + PcdCount), SignatureSize) == 0) {
if (EndChar == *(PcdTable + PcdCount + SignatureSize)) {
PcdPriority = *(PcdTable + PcdCount + SignatureSize + 1);
PcdFoundRegistered = TRUE;
break;
}
}
}
PcdCount++;
} while (PcdCount < PcdMaxCount);
if (PcdFoundRegistered) {
Status = mH2OIhisi->RegisterCommand (SubFuncTable[Index].CmdNumber, SubFuncTable[Index].IhisiFunction, PcdPriority);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_ERROR, "IHISI command :0x%X, priority : 0x%X, that already has a registered function\n", SubFuncTable[Index].CmdNumber, PcdPriority));
ASSERT (FALSE);
}
}
}
return Status;
}