444 lines
14 KiB
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;
|
|
}
|
|
|
|
|