2022-05-30 08:35:03 +03:00

139 lines
3.2 KiB
C

/** @file
OpenCore Variable library.
Copyright (c) 2021, Marvin Haeuser. All rights reserved.<BR>
SPDX-License-Identifier: BSD-3-Clause
**/
#include <Uefi.h>
#include <Guid/OcVariable.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcVariableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
STATIC BOOLEAN mForceOcWriteFlash = FALSE;
STATIC BOOLEAN mDebugInitialized = FALSE;
VOID
OcVariableInit (
IN BOOLEAN ForceOcWriteFlash
)
{
mForceOcWriteFlash = ForceOcWriteFlash;
DEBUG_CODE_BEGIN ();
mDebugInitialized = TRUE;
DEBUG_CODE_END ();
}
EFI_STATUS
OcSetSystemVariable (
IN CHAR16 *VariableName,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data,
IN EFI_GUID *VendorGuid OPTIONAL
)
{
EFI_STATUS Status;
INTN CmpResult;
UINTN OldDataSize;
VOID *OldData;
UINT8 StackBuffer[256];
if (VendorGuid == NULL) {
VendorGuid = &gOcVendorVariableGuid;
}
DEBUG_CODE_BEGIN ();
ASSERT (mDebugInitialized);
DEBUG_CODE_END ();
//
// All OC system variables are volatile as of now. Below logic must be adapted
// in case non-volatile requests are to be supported.
//
ASSERT ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0);
//
// If the data to be written is non-volatile, check first that the existing
// data is different. Handle errors tolerantly as this is only a shortcut.
//
if (mForceOcWriteFlash) {
//
// Try to read the old data to the stack first to save allocations.
//
OldDataSize = sizeof (StackBuffer);
OldData = StackBuffer;
Status = gRT->GetVariable (
VariableName,
VendorGuid,
NULL,
&OldDataSize,
OldData
);
if (Status == EFI_BUFFER_TOO_SMALL) {
//
// If the stack buffer is too small, allocate dynamically and retry.
//
OldData = AllocatePool (OldDataSize);
if (OldData != NULL) {
Status = gRT->GetVariable (
VariableName,
VendorGuid,
NULL,
&OldDataSize,
OldData
);
if (EFI_ERROR (Status)) {
FreePool (OldData);
}
}
}
if (!EFI_ERROR (Status)) {
//
// Status may only be a success value if the allocation did not fail.
//
ASSERT (OldData != NULL);
//
// Compare the current variable data to the new data to be written.
//
CmpResult = 1;
if (OldDataSize == DataSize) {
CmpResult = CompareMem (OldData, Data, DataSize);
}
if (OldData != StackBuffer) {
FreePool (OldData);
}
//
// If the old data is equal to the new data, skip the write.
//
if (CmpResult == 0) {
return EFI_SUCCESS;
}
}
//
// Force-write the OC system variable.
//
Attributes |= EFI_VARIABLE_NON_VOLATILE;
}
return gRT->SetVariable (
VariableName,
VendorGuid,
Attributes,
DataSize,
Data
);
}