alder_lake_bios/Insyde/InsydeModulePkg/Universal/Security/BiosProtectDxe/BiosProtectDxe.c

414 lines
13 KiB
C

/** @file
;******************************************************************************
;* Copyright (c) 2012 - 2019, Insyde Software Corp. 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.
;*
;******************************************************************************
*/
/*++
Module Name:
BiosProtectDxe.c
Abstract:
This driver registers event to enable BIOS region protection before boot to OS
--*/
#include <Uefi.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DxeChipsetSvcLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/H2OCpLib.h>
#include <Library/GenericBdsLib.h>
#include <Protocol/BiosRegionLock.h>
#include <Protocol/DxeSmmReadyToLock.h>
#include <Protocol/ExitPmAuth.h>
#include <Protocol/SmmBase2.h>
#include <Guid/EventGroup.h>
#include <Guid/EventLegacyBios.h>
#include <Guid/H2OBdsCheckPoint.h>
#include <SecureFlash.h>
/**
Bios protection stage 1 to calling BiosRegionLock protocol to set protected BIOS region and then lock.
@param [in] Event A pointer to the Event that triggered the callback.
@param [in] Context A pointer to private data registered with the callback function.
**/
VOID
EFIAPI
BiosProtectionStage1 (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
BIOS_REGION_LOCK_PROTOCOL *BiosRegionLock;
UINTN RegionIndex;
BIOS_PROTECT_REGION *BiosRegionTable;
UINT8 ProtectRegionNum;
STATIC BOOLEAN RegionLocked = FALSE;
ProtectRegionNum = 0;
BiosRegionLock = NULL;
BiosRegionTable = NULL;
if (Event != NULL) {
gBS->CloseEvent (Event);
} else {
H2OCpUnregisterHandler (Context);
}
Status = gBS->LocateProtocol (&gEfiBiosRegionLockProtocolGuid, NULL, (VOID **)&BiosRegionLock);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return;
}
if (RegionLocked) {
return;
}
RegionLocked = TRUE;
if (PcdGetBool (PcdSecureFlashSupported)) {
DxeCsSvcGetBiosProtectTable (&BiosRegionTable, &ProtectRegionNum);
if (BiosRegionTable != NULL && ProtectRegionNum != 0) {
for (RegionIndex = 0; RegionIndex < ProtectRegionNum; ++RegionIndex) {
Status = BiosRegionLock->SetRegionByAddress (BiosRegionLock, BiosRegionTable[RegionIndex].Base, BiosRegionTable[RegionIndex].Size);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "Secure flash support failed in this system!\n"));
FreePool (BiosRegionTable);
return;
}
}
FreePool (BiosRegionTable);
}
}
DEBUG ((EFI_D_ERROR | EFI_D_INFO, "Secure flash support succeed.\n"));
BiosRegionLock->Lock (BiosRegionLock);
}
/**
Bios protection stage 2 to installing ExitPmAuth protocol for chipset specific callback upon ready to boot
@param [in] Event A pointer to the Event that triggered the callback.
@param [in] Handle Checkpoint handle.
**/
VOID
EFIAPI
BiosProtectionStage2 (
IN EFI_EVENT Event,
IN H2O_CP_HANDLE Handle
)
{
EFI_STATUS Status;
VOID *Interface;
H2OCpUnregisterHandler (Handle);
//
// Install ExitPmAuth protocol for chipset specific callback
//
Interface = NULL;
Status = gBS->LocateProtocol (
&gExitPmAuthProtocolGuid,
NULL,
(VOID**)&Interface
);
if (EFI_ERROR (Status)) {
gBS->InstallProtocolInterface (
&gImageHandle,
&gExitPmAuthProtocolGuid,
EFI_NATIVE_INTERFACE,
NULL
);
}
}
/**
Bios protection stage 3 to installing DxeSmmReadyToLock protocol for boot script save lockdown
The timeframe of thsi callback being triggered is before SmmIpl ReadyToBootCallback
DxeSmmReadyToLockProtocol doorkeeper and after ChipsetPrepareReadyToBoot(for calling AcpiS3Save->S3Save())
@param [in] Event A pointer to the Event that triggered the callback.
@param [in] Context A pointer to private data registered with the callback function.
**/
VOID
EFIAPI
BiosProtectionStage3 (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
VOID *Interface;
gBS->CloseEvent (Event);
Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
if (!EFI_ERROR (Status)) {
return;
}
BdsLibTriggerDxeSmmReadyToLockEvent ();
}
/**
Bios protection notification registration callback, use to register event notifications to ensure the
callback can be triggered at last position of specific TPL level
@param [in] Event A pointer to the Event that triggered the callback.
@param [in] Context A pointer to private data registered with the callback function.
**/
VOID
EFIAPI
BiosProtectionEventHandler1 (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gBS->CloseEvent (Event);
//
// Register notification on TPL_CALLBACK of ReadyToBoot event for installing DxeSmmReadyToLockProtocol
// use for SMM lock to lockdown boot script save. The timeframe of this callback being triggered is
// before SmmIpl ReadyToBootCallback DxeSmmReadyToLockProtocol doorkeeper and after
// ChipsetPrepareReadyToBoot(for calling AcpiS3Save->S3Save())
//
EfiCreateEventReadyToBootEx (
TPL_CALLBACK,
BiosProtectionStage3,
NULL,
&Event
);
}
/**
Bios protection notification registration callback, use to register event notifications to ensure the
callback can be triggered at last position of specific TPL level
@param[in] Event A pointer to the Event that triggered the callback.
@param[in] Handle Checkpoint handle.
**/
VOID
EFIAPI
BiosProtectionEventHandler2 (
IN EFI_EVENT Event,
IN H2O_CP_HANDLE Handle
)
{
EFI_STATUS Status;
H2O_CP_HANDLE CpHandle;
H2OCpUnregisterHandler (Handle);
if (FeaturePcdGet (PcdH2OBdsCpDxeSmmReadyToLockBeforeSupported)) {
//
// Register checkpoint of gH2OBdsCpDxeSmmReadyToLockBeforeGuid to lockdown flash part protection
//
Status = H2OCpRegisterHandler (
&gH2OBdsCpDxeSmmReadyToLockBeforeGuid,
BiosProtectionStage1,
H2O_CP_MEDIUM_LOW,
&CpHandle
);
if (EFI_ERROR (Status)) {
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpDxeSmmReadyToLockBeforeGuid, Status));
return;
}
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpDxeSmmReadyToLockBeforeGuid, Status));
}
if (FeaturePcdGet (PcdH2OBdsCpReadyToBootBeforeSupported)) {
//
// Register checkpoint of BdsCpReadyToBootBefore to lockdown flash part protection
//
Status = H2OCpRegisterHandler (
&gH2OBdsCpReadyToBootBeforeGuid,
BiosProtectionStage1,
H2O_CP_MEDIUM_LOW,
&CpHandle
);
if (EFI_ERROR (Status)) {
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
return;
}
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
//
// Register notification on TPL_CALLBACK - 1 of BdsCpReadyToBootBefore event for installing ExitPmAuth protocol
// It is use for chipset specific callback upon ready to boot
//
Status = H2OCpRegisterHandler (
&gH2OBdsCpReadyToBootBeforeGuid,
BiosProtectionStage2,
H2O_CP_MEDIUM_LOW,
&CpHandle
);
if (EFI_ERROR (Status)) {
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
return;
}
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
}
}
/**
Bios protection notification registration callback, use to register event notifications to ensure the
callback can be triggered at last position of specific TPL level
@param [in] Event A pointer to the Event that triggered the callback.
@param [in] Context A pointer to private data registered with the callback function.
**/
VOID
EFIAPI
BiosProtectionEventHandler3 (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
VOID *Interface;
//
// Double check the interface installation
//
Status = gBS->LocateProtocol (
&gEfiSmmBase2ProtocolGuid,
NULL,
(VOID**)&Interface
);
if (!EFI_ERROR (Status)) {
gBS->CloseEvent (Event);
//
// Register notification on TPL_NOTIFY of gEfiEventDxeDispatchGuid events to ensure the entry point of SmmIpl driver is finish
// as the registration of the doorkeeper of DxeSmmReadyToLockProtocol upon ReadyToBoot event callback is after installation
// of SmmBase2 protocol
//
gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
BiosProtectionEventHandler1,
NULL,
&gEfiEventDxeDispatchGuid,
&Event
);
}
}
/**
This routine registers event to enable BIOS region protection.
@param [in] ImageHandle Handle for the image of this driver
@param [in] SystemTable Pointer to the EFI System Table
@retval EFI_SUCCESS The function completed successfully
**/
EFI_STATUS
EFIAPI
BiosProtectEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
VOID *Interface;
EFI_EVENT Event;
H2O_CP_HANDLE CpHandle;
if (!FeaturePcdGet(PcdInstantCapsuleUpdateSupported)) {
if (FeaturePcdGet (PcdH2OBdsCpInitSupported)) {
//
// Register notification on TPL_NOTIFY of gH2OBdsCpInitGuid event to register other notifications
// to ensure the callbacks can be triggered at last position of specific TPL level
//
Status = H2OCpRegisterHandler (
&gH2OBdsCpInitGuid,
BiosProtectionEventHandler2,
H2O_CP_HIGH,
&CpHandle
);
if (EFI_ERROR (Status)) {
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpInitGuid, Status));
return Status;
}
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpInitGuid, Status));
}
Status = gBS->LocateProtocol (
&gEfiSmmBase2ProtocolGuid,
NULL,
&Interface
);
if (!EFI_ERROR (Status)) {
//
// Go ahead directly to register proper handler
//
BiosProtectionEventHandler1 (NULL, NULL);
} else {
//
// Register notification for SmmBase2
//
EfiCreateProtocolNotifyEvent (
&gEfiSmmBase2ProtocolGuid,
TPL_NOTIFY,
BiosProtectionEventHandler3,
NULL,
&Interface
);
}
} else {
//
// Register notification on TPL_NOTIFY of LegacyBoot/ExitBootServices events to lockdown flash part protection
// Postpone the event after boot loader get called for instant capsule update
//
gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
BiosProtectionStage1,
NULL,
&gEfiEventLegacyBootGuid,
&Event
);
gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
BiosProtectionStage1,
NULL,
&gEfiEventExitBootServicesGuid,
&Event
);
if (FeaturePcdGet (PcdH2OBdsCpReadyToBootBeforeSupported)) {
//
// Register notification on TPL_CALLBACK of LegacyBoot/ExitBootServices for installing ExitPmAuth protocol
// It is use for chipset specific callback upon ready to boot
//
Status = H2OCpRegisterHandler (
&gH2OBdsCpReadyToBootBeforeGuid,
BiosProtectionStage2,
H2O_CP_MEDIUM_LOW,
&CpHandle
);
if (EFI_ERROR (Status)) {
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
return Status;
}
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
}
}
return EFI_SUCCESS;
}