/** @file
Copyright (c) 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "S3NvramSave.h"
#include
#include
#include
/**
This function will retrieve the S3 data from HOBs produced by MRC
and will save it to NVRAM if the data is absent or different from
the previously saved data.
@param VOID
@retval VOID
**/
VOID
SaveS3StructToNvram (
VOID
)
{
EFI_STATUS Status;
UINTN BufferSize;
UINTN CurrentHobSize;
UINTN S3ChunkSize;
CHAR16 EfiMemoryConfigVariable[] = L"MemoryConfig0";
EFI_HOB_GUID_TYPE *GuidHob = NULL;
VOID *HobData = NULL;
VOID *VariableData = NULL;
UINTN CompressedDataSize;
UINT32 ScratchSize;
VOID *CompressedData = NULL;
VOID *Scratch = NULL;
EFI_DECOMPRESS_PROTOCOL *Decompress = NULL;
VOID *CompressedVariableData = NULL;
UINTN CompressedBufferSize;
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock = NULL;
//
// Get first S3 data HOB
//
GuidHob = GetFirstGuidHob (&gEfiMemoryConfigDataHobGuid);
Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
DEBUG((DEBUG_INFO, "[SaveMemoryConfigEntryPoint] Locate Decompress protocol - %r\n", Status));
if(EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return;
}
Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
DEBUG((DEBUG_INFO, "[SaveMemoryConfigEntryPoint] Locate Variable Lock protocol - %r\n", Status));
ASSERT_EFI_ERROR(Status);
while (TRUE) {
if (GuidHob == NULL) {
break;
}
HobData = GET_GUID_HOB_DATA(GuidHob);
CurrentHobSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
DEBUG((EFI_D_INFO, " Current Hob Size(bytes) is: %d\n", CurrentHobSize));
//
// Use the HOB data to save Memory Configuration Data
//
BufferSize = CurrentHobSize;
Status = gBS->AllocatePool (
EfiBootServicesData,
BufferSize,
(VOID**)&VariableData
);
ASSERT (VariableData != NULL);
S3ChunkSize = MAX_HOB_ENTRY_SIZE / 8;
DEBUG((EFI_D_INFO, " S3ChunkSize Hob Size(bytes): %d\n", S3ChunkSize));
while (CurrentHobSize) {
if (S3ChunkSize > CurrentHobSize) {
S3ChunkSize = CurrentHobSize;
}
BufferSize = S3ChunkSize;
CompressedDataSize = 0;
ScratchSize = 0;
Status = gRT->GetVariable (
EfiMemoryConfigVariable,
&gEfiMemoryConfigDataGuid,
NULL,
&CompressedDataSize,
NULL
);
if(Status == EFI_BUFFER_TOO_SMALL) {
Status = gBS->AllocatePool (
EfiBootServicesData,
CompressedDataSize,
(VOID**)&CompressedData
);
ASSERT (Status == EFI_SUCCESS);
}
if(!EFI_ERROR (Status))
{
Status = gRT->GetVariable (
EfiMemoryConfigVariable,
&gEfiMemoryConfigDataGuid,
NULL,
&CompressedDataSize,
CompressedData
);
if (!EFI_ERROR (Status)) {
Status = Decompress->GetInfo (
Decompress,
CompressedData,
(UINT32)CompressedDataSize,
(UINT32*)&BufferSize,
&ScratchSize
);
}
if (!EFI_ERROR (Status)) {
Status = gBS->AllocatePool (
EfiBootServicesData,
ScratchSize,
(VOID**)&Scratch
);
}
if (!EFI_ERROR (Status)) {
Status = Decompress->Decompress (
Decompress,
CompressedData,
(UINT32)CompressedDataSize,
VariableData,
(UINT32)BufferSize,
Scratch,
ScratchSize
);
}
if (EFI_ERROR (Status)) {
DEBUG((EFI_D_ERROR, "Getting variables error: 0x%x\n", Status));
ASSERT (Status == EFI_SUCCESS);
}
if(Scratch != NULL) {
gBS->FreePool (Scratch);
Scratch = NULL;
}
}
if(CompressedData != NULL) {
gBS->FreePool (CompressedData);
CompressedData = NULL;
}
if ( (EFI_ERROR(Status)) || (CompareMem (HobData, VariableData, S3ChunkSize) != 0) ) {
Status = gBS->AllocatePool (
EfiBootServicesData,
BufferSize,
(VOID**)&CompressedVariableData
);
ASSERT (CompressedVariableData != NULL);
if (Status == EFI_SUCCESS) {
CompressedBufferSize = BufferSize;
Status = Compress(HobData, S3ChunkSize, CompressedVariableData, &CompressedBufferSize);
if (Status == EFI_BUFFER_TOO_SMALL){
gBS->FreePool(CompressedVariableData);
Status = gBS->AllocatePool(
EfiBootServicesData,
CompressedBufferSize,
(VOID**)&CompressedVariableData
);
ASSERT (CompressedVariableData != NULL);
Status = Compress(HobData, S3ChunkSize, CompressedVariableData, &CompressedBufferSize);
}
if(Status == EFI_SUCCESS) {
Status = gRT->SetVariable (
EfiMemoryConfigVariable,
&gEfiMemoryConfigDataGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
CompressedBufferSize,
CompressedVariableData
);
}
if(CompressedVariableData != NULL) {
gBS->FreePool(CompressedVariableData);
CompressedVariableData = NULL;
}
}
if (EFI_ERROR (Status)) {
DEBUG((EFI_D_ERROR, "Set variable error. Status: 0x%x\n", Status));
ASSERT_EFI_ERROR (Status);
}
}
//
// Lock the Memory Config Variable
//
Status = VariableLock->RequestToLock(VariableLock, EfiMemoryConfigVariable, &gEfiMemoryConfigDataGuid);
ASSERT_EFI_ERROR(Status);
HobData = (UINT8 *) (HobData) + S3ChunkSize;
CurrentHobSize -= S3ChunkSize;
EfiMemoryConfigVariable[12]++; // Increment number in the string
}
//
// Get next S3 Config data hob, if none left, results NULL
//
GuidHob = GET_NEXT_HOB (GuidHob); // Increment to next HOB
GuidHob = GetNextGuidHob (&gEfiMemoryConfigDataHobGuid, GuidHob); // Now search for next MemConfig HOB
if(VariableData != NULL) {
gBS->FreePool(VariableData);
VariableData = NULL;
}
}
return;
}
EFI_STATUS
EFIAPI
S3NvramSaveEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/**
This is the main entry point of the S3 NVRAM Save module.
@param ImageHandle - Handle for the image of this driver.
@param SystemTable - Pointer to the EFI System Table.
@retval EFI_SUCCESS - Module launched successfully.
**/
{
EFI_STATUS Status = EFI_SUCCESS;
//
// Save the s3 strututre from MRC into NVRAM if needed
//
SaveS3StructToNvram();
return Status;
}