summaryrefslogtreecommitdiff
path: root/Platform/Intel/PurleyOpenBoardPkg/Policy/S3NvramSave/S3NvramSave.c
diff options
context:
space:
mode:
Diffstat (limited to 'Platform/Intel/PurleyOpenBoardPkg/Policy/S3NvramSave/S3NvramSave.c')
-rw-r--r--Platform/Intel/PurleyOpenBoardPkg/Policy/S3NvramSave/S3NvramSave.c262
1 files changed, 262 insertions, 0 deletions
diff --git a/Platform/Intel/PurleyOpenBoardPkg/Policy/S3NvramSave/S3NvramSave.c b/Platform/Intel/PurleyOpenBoardPkg/Policy/S3NvramSave/S3NvramSave.c
new file mode 100644
index 0000000000..27d5efbeef
--- /dev/null
+++ b/Platform/Intel/PurleyOpenBoardPkg/Policy/S3NvramSave/S3NvramSave.c
@@ -0,0 +1,262 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "S3NvramSave.h"
+#include <Protocol/Decompress.h>
+#include <Library/CompressLib.h>
+#include <Protocol/VariableLock.h>
+
+/**
+
+ 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;
+
+}