2021-09-22 23:27:21 +02:00
|
|
|
/** @file
|
|
|
|
This driver is used for SMM S3 support for the bootloader that
|
|
|
|
doesn't support SMM.
|
|
|
|
The payload would save SMM rebase info to SMM communication area.
|
|
|
|
The bootloader is expected to rebase the SMM and trigger SMI by
|
|
|
|
writting 0xB2 port with given value from SMM communication area.
|
|
|
|
The paylaod SMM handler got chance to restore regs in S3 path.
|
|
|
|
|
|
|
|
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include <BlSupportSmm.h>
|
|
|
|
|
|
|
|
PLD_S3_COMMUNICATION mPldS3Hob;
|
|
|
|
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *mSmramHob = NULL;
|
|
|
|
PLD_SMM_REGISTERS *mSmmRegisterHob = NULL;
|
|
|
|
UINT64 mSmmFeatureControl = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
Save SMM rebase and SMI handler information to SMM communication area
|
|
|
|
|
|
|
|
The function detects SMM communication region for boot loader, if it is detected, it
|
|
|
|
will save SMM rebase information and S3 SMI handler information to SMM communication
|
|
|
|
region. Bootloader should consume these information in S3 path to restore smm base,
|
|
|
|
and write the 0xB2 port to trigger SMI so that payload could resume S3 registers.
|
|
|
|
|
|
|
|
@param[in] BlSwSmiHandlerInput Value written to 0xB2 to trigger SMI handler.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Save SMM info success.
|
|
|
|
@retval Others Failed to save SMM info.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
SaveSmmInfoForS3 (
|
|
|
|
IN UINT8 BlSwSmiHandlerInput
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_PROCESSOR_INFORMATION ProcessorInfo;
|
|
|
|
EFI_MP_SERVICES_PROTOCOL *MpService;
|
|
|
|
CPU_SMMBASE *SmmBaseInfo;
|
|
|
|
PLD_TO_BL_SMM_INFO *PldSmmInfo;
|
|
|
|
UINTN Index;
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
PldSmmInfo = (PLD_TO_BL_SMM_INFO *)(UINTN)mPldS3Hob.CommBuffer.PhysicalStart;
|
|
|
|
PldSmmInfo->Header.Header.HobLength = (UINT16)(sizeof (PLD_TO_BL_SMM_INFO) + gSmst->NumberOfCpus * sizeof (CPU_SMMBASE));
|
|
|
|
for (Index = 0; Index < mSmramHob->NumberOfSmmReservedRegions; Index++) {
|
|
|
|
if ((mPldS3Hob.CommBuffer.PhysicalStart >= mSmramHob->Descriptor[Index].PhysicalStart) &&
|
|
|
|
(mPldS3Hob.CommBuffer.PhysicalStart < mSmramHob->Descriptor[Index].PhysicalStart + mSmramHob->Descriptor[Index].PhysicalSize))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
if (Index == mSmramHob->NumberOfSmmReservedRegions) {
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Make sure the dedicated region for SMM info communication whose attribute is "allocated" (i.e., excluded from SMM memory service)
|
|
|
|
//
|
|
|
|
if ((mSmramHob->Descriptor[Index].RegionState & EFI_ALLOCATED) == 0) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "SMM communication region not set to EFI_ALLOCATED\n"));
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (((UINTN)PldSmmInfo + PldSmmInfo->Header.Header.HobLength) > (mSmramHob->Descriptor[Index].PhysicalStart + mSmramHob->Descriptor[Index].PhysicalSize)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "SMM communication buffer (0x%x) is too small.\n", (UINTN)PldSmmInfo + PldSmmInfo->Header.Header.HobLength));
|
|
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyGuid (&PldSmmInfo->Header.Name, &gS3CommunicationGuid);
|
|
|
|
PldSmmInfo->Header.Header.HobType = EFI_HOB_TYPE_GUID_EXTENSION;
|
|
|
|
PldSmmInfo->S3Info.SwSmiTriggerValue = BlSwSmiHandlerInput;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Save APIC ID and SMM base
|
|
|
|
//
|
|
|
|
Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
PldSmmInfo->S3Info.CpuCount = (UINT32)gSmst->NumberOfCpus;
|
|
|
|
SmmBaseInfo = &PldSmmInfo->S3Info.SmmBase[0];
|
|
|
|
for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
|
|
|
|
Status = MpService->GetProcessorInfo (MpService, Index, &ProcessorInfo);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
SmmBaseInfo->ApicId = (UINT32)(UINTN)ProcessorInfo.ProcessorId;
|
|
|
|
SmmBaseInfo->SmmBase = (UINT32)(UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET;
|
|
|
|
DEBUG ((DEBUG_INFO, "CPU%d ID:%02X Base: %08X\n", Index, SmmBaseInfo->ApicId, SmmBaseInfo->SmmBase));
|
|
|
|
SmmBaseInfo++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Get specified SMI register based on given register ID
|
|
|
|
|
|
|
|
@param[in] Id The register ID to get.
|
|
|
|
|
|
|
|
@retval NULL The register is not found
|
|
|
|
@return smi register
|
|
|
|
|
|
|
|
**/
|
|
|
|
PLD_GENERIC_REGISTER *
|
|
|
|
GetRegisterById (
|
|
|
|
UINT64 Id
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT32 Index;
|
|
|
|
|
|
|
|
for (Index = 0; Index < mSmmRegisterHob->Count; Index++) {
|
|
|
|
if (mSmmRegisterHob->Registers[Index].Id == Id) {
|
|
|
|
return &mSmmRegisterHob->Registers[Index];
|
|
|
|
}
|
|
|
|
}
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Set SMM SMI Global enable lock
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
LockSmiGlobalEn (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
PLD_GENERIC_REGISTER *SmiLockReg;
|
|
|
|
|
|
|
|
DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn .....\n"));
|
|
|
|
|
|
|
|
SmiLockReg = GetRegisterById (REGISTER_ID_SMI_GBL_EN_LOCK);
|
|
|
|
if (SmiLockReg == NULL) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "SMI global enable lock reg not found.\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set SMM SMI lock in S3 path
|
|
|
|
//
|
|
|
|
if ((SmiLockReg->Address.AccessSize == EFI_ACPI_3_0_DWORD) &&
|
|
|
|
(SmiLockReg->Address.Address != 0) &&
|
|
|
|
(SmiLockReg->Address.RegisterBitWidth == 1) &&
|
|
|
|
(SmiLockReg->Address.AddressSpaceId == EFI_ACPI_3_0_SYSTEM_MEMORY) &&
|
|
|
|
(SmiLockReg->Value == 1))
|
|
|
|
{
|
|
|
|
DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn ....is locked\n"));
|
|
|
|
|
|
|
|
MmioOr32 ((UINT32)SmiLockReg->Address.Address, 1 << SmiLockReg->Address.RegisterBitOffset);
|
|
|
|
} else {
|
|
|
|
DEBUG ((DEBUG_ERROR, "Unexpected SMM SMI lock register, need enhancement here.\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Check and set SMM feature lock bit and code check enable bit
|
|
|
|
in S3 path.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
SmmFeatureLockOnS3 (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (mSmmFeatureControl != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mSmmFeatureControl = AsmReadMsr64 (MSR_SMM_FEATURE_CONTROL);
|
|
|
|
if ((mSmmFeatureControl & 0x5) != 0x5) {
|
|
|
|
//
|
|
|
|
// Set Lock bit [BIT0] for this register and SMM code check enable bit [BIT2]
|
|
|
|
//
|
|
|
|
AsmWriteMsr64 (MSR_SMM_FEATURE_CONTROL, mSmmFeatureControl | 0x5);
|
|
|
|
}
|
|
|
|
|
|
|
|
mSmmFeatureControl = AsmReadMsr64 (MSR_SMM_FEATURE_CONTROL);
|
2021-12-05 23:54:18 +01:00
|
|
|
}
|
2021-09-22 23:27:21 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
Function to program SMRR base and mask.
|
|
|
|
|
|
|
|
@param[in] ProcedureArgument Pointer to SMRR_BASE_MASK structure.
|
|
|
|
**/
|
|
|
|
VOID
|
2022-02-23 23:55:19 +01:00
|
|
|
EFIAPI
|
2021-09-22 23:27:21 +02:00
|
|
|
SetSmrr (
|
|
|
|
IN VOID *ProcedureArgument
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (ProcedureArgument != NULL) {
|
|
|
|
AsmWriteMsr64 (MSR_IA32_SMRR_PHYSBASE, ((SMRR_BASE_MASK *)ProcedureArgument)->Base);
|
|
|
|
AsmWriteMsr64 (MSR_IA32_SMRR_PHYSMASK, ((SMRR_BASE_MASK *)ProcedureArgument)->Mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Set SMRR in S3 path.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
SetSmrrOnS3 (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
SMRR_BASE_MASK Arguments;
|
|
|
|
UINTN Index;
|
|
|
|
UINT32 SmmBase;
|
|
|
|
UINT32 SmmSize;
|
|
|
|
|
|
|
|
if ((AsmReadMsr64 (MSR_IA32_SMRR_PHYSBASE) != 0) && ((AsmReadMsr64 (MSR_IA32_SMRR_PHYSMASK) & BIT11) != 0)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SmmBase = (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalStart;
|
|
|
|
SmmSize = (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalSize;
|
|
|
|
if ((mSmramHob->NumberOfSmmReservedRegions > 2) || (mSmramHob->NumberOfSmmReservedRegions == 0)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "%d SMM ranges are not supported.\n", mSmramHob->NumberOfSmmReservedRegions));
|
|
|
|
return;
|
|
|
|
} else if (mSmramHob->NumberOfSmmReservedRegions == 2) {
|
|
|
|
if ((mSmramHob->Descriptor[1].PhysicalStart + mSmramHob->Descriptor[1].PhysicalSize) == SmmBase) {
|
|
|
|
SmmBase = (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalStart;
|
|
|
|
} else if (mSmramHob->Descriptor[1].PhysicalStart != (SmmBase + SmmSize)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "Two SMM regions are not continous.\n"));
|
|
|
|
return;
|
|
|
|
}
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
SmmSize += (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((SmmBase == 0) || (SmmSize < SIZE_4KB)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "Invalid SMM range.\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// SMRR size must be of length 2^n
|
|
|
|
// SMRR base alignment cannot be less than SMRR length
|
|
|
|
//
|
|
|
|
if ((SmmSize != GetPowerOfTwo32 (SmmSize)) || ((SmmBase & ~(SmmSize - 1)) != SmmBase)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, " Invalid SMM range.\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Calculate smrr base, mask and pass them as arguments.
|
|
|
|
//
|
|
|
|
Arguments.Base = (SmmSize | MTRR_CACHE_WRITE_BACK);
|
|
|
|
Arguments.Mask = (~(SmmSize - 1) & EFI_MSR_SMRR_MASK);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set SMRR valid bit
|
|
|
|
//
|
|
|
|
Arguments.Mask |= BIT11;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Program smrr base and mask on BSP first and then on APs
|
|
|
|
//
|
|
|
|
SetSmrr (&Arguments);
|
|
|
|
for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
|
|
|
|
if (Index != gSmst->CurrentlyExecutingCpu) {
|
|
|
|
Status = gSmst->SmmStartupThisAp (SetSmrr, Index, (VOID *)&Arguments);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "Programming SMRR on AP# %d status: %r\n", Index, Status));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Software SMI callback for restoring SMRR base and mask in S3 path.
|
|
|
|
|
|
|
|
@param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
|
|
|
|
@param[in] Context Points to an optional handler context which was specified when the
|
|
|
|
handler was registered.
|
|
|
|
@param[in, out] CommBuffer A pointer to a collection of data in memory that will
|
|
|
|
be conveyed from a non-SMM environment into an SMM environment.
|
|
|
|
@param[in, out] CommBufferSize The size of the CommBuffer.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The interrupt was handled successfully.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
BlSwSmiHandler (
|
|
|
|
IN EFI_HANDLE DispatchHandle,
|
|
|
|
IN CONST VOID *Context,
|
|
|
|
IN OUT VOID *CommBuffer,
|
|
|
|
IN OUT UINTN *CommBufferSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
SetSmrrOnS3 ();
|
|
|
|
SmmFeatureLockOnS3 ();
|
|
|
|
LockSmiGlobalEn ();
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Lock SMI in this SMM ready to lock event.
|
|
|
|
|
|
|
|
@param Protocol Points to the protocol's unique identifier
|
|
|
|
@param Interface Points to the interface instance
|
|
|
|
@param Handle The handle on which the interface was installed
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS SmmEventCallback runs successfully
|
|
|
|
@retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
BlSupportSmmReadyToLockCallback (
|
|
|
|
IN CONST EFI_GUID *Protocol,
|
|
|
|
IN VOID *Interface,
|
|
|
|
IN EFI_HANDLE Handle
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Set SMM SMI lock
|
|
|
|
//
|
|
|
|
LockSmiGlobalEn ();
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
The driver's entry point.
|
|
|
|
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
|
|
@retval Others Some error occurs when executing this entry point.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
BlSupportSmm (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
|
|
|
|
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
|
|
|
|
EFI_HANDLE SwHandle;
|
|
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
|
|
VOID *SmmHob;
|
|
|
|
VOID *Registration;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get SMM S3 communication hob and save it
|
|
|
|
//
|
|
|
|
GuidHob = GetFirstGuidHob (&gS3CommunicationGuid);
|
|
|
|
if (GuidHob != NULL) {
|
|
|
|
SmmHob = (VOID *)(GET_GUID_HOB_DATA (GuidHob));
|
|
|
|
CopyMem (&mPldS3Hob, SmmHob, GET_GUID_HOB_DATA_SIZE (GuidHob));
|
|
|
|
} else {
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mPldS3Hob.PldAcpiS3Enable) {
|
|
|
|
// Other drivers will take care of S3.
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get smram hob and save it
|
|
|
|
//
|
|
|
|
GuidHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);
|
|
|
|
if (GuidHob != NULL) {
|
|
|
|
SmmHob = (VOID *)(GET_GUID_HOB_DATA (GuidHob));
|
|
|
|
mSmramHob = AllocatePool (GET_GUID_HOB_DATA_SIZE (GuidHob));
|
|
|
|
if (mSmramHob == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
CopyMem (mSmramHob, SmmHob, GET_GUID_HOB_DATA_SIZE (GuidHob));
|
|
|
|
} else {
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get SMM register hob and save it
|
|
|
|
//
|
|
|
|
GuidHob = GetFirstGuidHob (&gSmmRegisterInfoGuid);
|
|
|
|
if (GuidHob != NULL) {
|
|
|
|
SmmHob = (VOID *)(GET_GUID_HOB_DATA (GuidHob));
|
|
|
|
mSmmRegisterHob = AllocatePool (GET_GUID_HOB_DATA_SIZE (GuidHob));
|
|
|
|
if (mSmmRegisterHob == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
CopyMem (mSmmRegisterHob, SmmHob, GET_GUID_HOB_DATA_SIZE (GuidHob));
|
|
|
|
} else {
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get the Sw dispatch protocol and register SMI handler.
|
|
|
|
//
|
|
|
|
Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **)&SwDispatch);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
2021-12-05 23:54:18 +01:00
|
|
|
|
2021-09-22 23:27:21 +02:00
|
|
|
SwContext.SwSmiInputValue = (UINTN)-1;
|
|
|
|
Status = SwDispatch->Register (SwDispatch, BlSwSmiHandler, &SwContext, &SwHandle);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((DEBUG_ERROR, "Registering S3 smi handler failed: %r\n", Status));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register SMM ready to lock callback
|
|
|
|
//
|
|
|
|
Status = gSmst->SmmRegisterProtocolNotify (
|
|
|
|
&gEfiSmmReadyToLockProtocolGuid,
|
|
|
|
BlSupportSmmReadyToLockCallback,
|
|
|
|
&Registration
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
SaveSmmInfoForS3 ((UINT8)SwContext.SwSmiInputValue);
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|