/** @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; }