/** @file OpenCore Variable library. Copyright (c) 2021, Marvin Haeuser. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause **/ #include #include #include #include #include #include #include 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 ); }