X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=SecurityPkg%2FVariableAuthenticated%2FRuntimeDxe%2FVariable.c;h=53ef092aff951d9eebf3e676c229dca39c2f2bd9;hp=ebe04b50f5bd2d710e05ace2d67138e33ed18db7;hb=6e67fec07f7fe4033da696eb2d08c5617edaa590;hpb=56251c669f0f13d2ffc226cfd3a3d8c5f8269e7a diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c index ebe04b50f5..53ef092aff 100644 --- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c @@ -35,12 +35,28 @@ VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; /// /// Define a memory cache that improves the search performance for a variable. /// -VARIABLE_STORE_HEADER *mNvVariableCache = NULL; +VARIABLE_STORE_HEADER *mNvVariableCache = NULL; /// /// The memory entry used for variable statistics data. /// -VARIABLE_INFO_ENTRY *gVariableInfo = NULL; +VARIABLE_INFO_ENTRY *gVariableInfo = NULL; + +/// +/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID +/// or EVT_GROUP_READY_TO_BOOT event. +/// +LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList); + +/// +/// The flag to indicate whether the platform has left the DXE phase of execution. +/// +BOOLEAN mEndOfDxe = FALSE; + +/// +/// The flag to indicate whether the variable storage locking is enabled. +/// +BOOLEAN mEnableLocking = TRUE; /** @@ -1649,7 +1665,7 @@ UpdateVariable ( EFI_STATUS Status; VARIABLE_HEADER *NextVariable; UINTN ScratchSize; - UINTN ScratchDataSize; + UINTN MaxDataSize; UINTN NonVolatileVarableStoreSize; UINTN VarNameOffset; UINTN VarDataOffset; @@ -1664,7 +1680,6 @@ UpdateVariable ( UINTN CacheOffset; UINTN BufSize; UINTN DataOffset; - UINTN RevBufSize; if (mVariableModuleGlobal->FvbInstance == NULL) { // @@ -1713,7 +1728,7 @@ UpdateVariable ( // NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)); ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); - ScratchDataSize = ScratchSize - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName)); + if (Variable->CurrPtr != NULL) { // @@ -1827,14 +1842,36 @@ UpdateVariable ( DataOffset = sizeof (VARIABLE_HEADER) + Variable->CurrPtr->NameSize + GET_PAD_SIZE (Variable->CurrPtr->NameSize); CopyMem (mStorageArea, (UINT8*)((UINTN) Variable->CurrPtr + DataOffset), Variable->CurrPtr->DataSize); + // + // Set Max Common Variable Data Size as default MaxDataSize + // + MaxDataSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName)); + + if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) || (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) { + // // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of // EFI_SIGNATURE_DATA values that are already part of the existing variable value. // - BufSize = AppendSignatureList (mStorageArea, Variable->CurrPtr->DataSize, Data, DataSize); + Status = AppendSignatureList ( + mStorageArea, + Variable->CurrPtr->DataSize, + MaxDataSize - Variable->CurrPtr->DataSize, + Data, + DataSize, + &BufSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Signture List is too long, Failed to Append + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + if (BufSize == Variable->CurrPtr->DataSize) { if ((TimeStamp == NULL) || CompareTimeStamp (TimeStamp, &Variable->CurrPtr->TimeStamp)) { // @@ -1849,20 +1886,23 @@ UpdateVariable ( } else { // // For other Variables, append the new data to the end of previous data. + // Max Harware error record variable data size is different from common variable // + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName)); + } + + if (Variable->CurrPtr->DataSize + DataSize > MaxDataSize) { + // + // Exsiting data + Appended data exceed maximum variable size limitation + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } CopyMem ((UINT8*)((UINTN) mStorageArea + Variable->CurrPtr->DataSize), Data, DataSize); BufSize = Variable->CurrPtr->DataSize + DataSize; } - RevBufSize = MIN (PcdGet32 (PcdMaxVariableSize), ScratchDataSize); - if (BufSize > RevBufSize) { - // - // If variable size (previous + current) is bigger than reserved buffer in runtime, - // return EFI_OUT_OF_RESOURCES. - // - return EFI_OUT_OF_RESOURCES; - } - // // Override Data and DataSize which are used for combined data area including previous and new data. // @@ -2287,6 +2327,58 @@ IsHwErrRecVariable ( return TRUE; } +/** + Mark a variable that will become read-only after leaving the DXE phase of execution. + + @param[in] This The VARIABLE_LOCK_PROTOCOL instance. + @param[in] VariableName A pointer to the variable name that will be made read-only subsequently. + @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently. + + @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked + as pending to be read-only. + @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL. + Or VariableName is an empty string. + @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has + already been signaled. + @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request. +**/ +EFI_STATUS +EFIAPI +VariableLockRequestToLock ( + IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This, + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + VARIABLE_ENTRY *Entry; + + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mEndOfDxe) { + return EFI_ACCESS_DENIED; + } + + Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName)); + if (Entry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName)); + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + Entry->Name = (CHAR16 *) (Entry + 1); + StrCpy (Entry->Name, VariableName); + CopyGuid (&Entry->Guid, VendorGuid); + InsertTailList (&mLockedVariableList, &Entry->Link); + + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + return EFI_SUCCESS; +} + /** This code checks if variable should be treated as read-only variable. @@ -2603,6 +2695,8 @@ VariableServiceSetVariable ( VARIABLE_HEADER *NextVariable; EFI_PHYSICAL_ADDRESS Point; UINTN PayloadSize; + LIST_ENTRY *Link; + VARIABLE_ENTRY *Entry; // // Check input parameters. @@ -2693,16 +2787,6 @@ VariableServiceSetVariable ( } } - if (AtRuntime ()) { - // - // HwErrRecSupport Global Variable identifies the level of hardware error record persistence - // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS. - // - if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) { - return EFI_WRITE_PROTECTED; - } - } - AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); // @@ -2721,13 +2805,41 @@ VariableServiceSetVariable ( mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point; } + if (mEndOfDxe && mEnableLocking) { + // + // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase. + // + for ( Link = GetFirstNode (&mLockedVariableList) + ; !IsNull (&mLockedVariableList, Link) + ; Link = GetNextNode (&mLockedVariableList, Link) + ) { + Entry = BASE_CR (Link, VARIABLE_ENTRY, Link); + if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Entry->Name, VariableName) == 0)) { + Status = EFI_WRITE_PROTECTED; + DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName)); + goto Done; + } + } + } + // // Check whether the input variable is already existed. // Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE); if (!EFI_ERROR (Status)) { if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) { - return EFI_WRITE_PROTECTED; + Status = EFI_WRITE_PROTECTED; + goto Done; + } + if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) { + // + // If a preexisting variable is rewritten with different attributes, SetVariable() shall not + // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule: + // 1. No access attributes specified + // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE + // + Status = EFI_INVALID_PARAMETER; + goto Done; } } @@ -2752,6 +2864,7 @@ VariableServiceSetVariable ( Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes); } +Done: InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState); ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); @@ -2965,6 +3078,135 @@ ReclaimForOS( } } +/** + Init non-volatile variable store. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted. + +**/ +EFI_STATUS +InitNonVolatileVariableStore ( + VOID + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + VARIABLE_HEADER *NextVariable; + EFI_PHYSICAL_ADDRESS VariableStoreBase; + UINT64 VariableStoreLength; + UINTN VariableSize; + EFI_HOB_GUID_TYPE *GuidHob; + EFI_PHYSICAL_ADDRESS NvStorageBase; + UINT8 *NvStorageData; + UINT32 NvStorageSize; + FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData; + UINT32 BackUpOffset; + UINT32 BackUpSize; + + mVariableModuleGlobal->FvbInstance = NULL; + + // + // Note that in EdkII variable driver implementation, Hardware Error Record type variable + // is stored with common variable in the same NV region. So the platform integrator should + // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of + // PcdFlashNvStorageVariableSize. + // + ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize)); + + // + // Allocate runtime memory used for a memory copy of the FLASH region. + // Keep the memory and the FLASH in sync as updates occur. + // + NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize); + NvStorageData = AllocateRuntimeZeroPool (NvStorageSize); + if (NvStorageData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (NvStorageBase == 0) { + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); + } + // + // Copy NV storage data to the memory buffer. + // + CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize); + + // + // Check the FTW last write data hob. + // + GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid); + if (GuidHob != NULL) { + FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob); + if (FtwLastWriteData->TargetAddress == NvStorageBase) { + DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress)); + // + // Copy the backed up NV storage data to the memory buffer from spare block. + // + CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize); + } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && + (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) { + // + // Flash NV storage from the Offset is backed up in spare block. + // + BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase); + BackUpSize = NvStorageSize - BackUpOffset; + DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress)); + // + // Copy the partial backed up NV storage data to the memory buffer from spare block. + // + CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize); + } + } + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData; + + // + // Check if the Firmware Volume is not corrupted + // + if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) { + FreePool (NvStorageData); + DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n")); + return EFI_VOLUME_CORRUPTED; + } + + VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength); + VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength); + + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; + mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase; + if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) { + FreePool (NvStorageData); + DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n")); + return EFI_VOLUME_CORRUPTED; + } + ASSERT(mNvVariableCache->Size == VariableStoreLength); + + // + // The max variable or hardware error variable size should be < variable store size. + // + ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength); + + // + // Parse non-volatile variable data and get last variable offset. + // + NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase); + while (IsValidVariableHeader (NextVariable)) { + VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER); + if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize); + } else { + mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize); + } + + NextVariable = GetNextVariablePtr (NextVariable); + } + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase; + + return EFI_SUCCESS; +} + /** Flush the HOB variable to flash. @@ -3056,7 +3298,7 @@ FlushHobVariableToFlash ( } /** - Initializes variable write service after FVB was ready. + Initializes variable write service after FTW was ready. @retval EFI_SUCCESS Function successfully executed. @retval Others Fail to initialize the variable service. @@ -3072,8 +3314,18 @@ VariableWriteServiceInitialize ( UINTN Index; UINT8 Data; EFI_PHYSICAL_ADDRESS VariableStoreBase; + EFI_PHYSICAL_ADDRESS NvStorageBase; - VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (NvStorageBase == 0) { + NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); + } + VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength); + + // + // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready. + // + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; // @@ -3126,12 +3378,8 @@ VariableCommonInitialize ( EFI_STATUS Status; VARIABLE_STORE_HEADER *VolatileVariableStore; VARIABLE_STORE_HEADER *VariableStoreHeader; - VARIABLE_HEADER *NextVariable; - EFI_PHYSICAL_ADDRESS TempVariableStoreHeader; - EFI_PHYSICAL_ADDRESS VariableStoreBase; UINT64 VariableStoreLength; UINTN ScratchSize; - UINTN VariableSize; EFI_HOB_GUID_TYPE *GuidHob; // @@ -3144,14 +3392,6 @@ VariableCommonInitialize ( InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY); - // - // Note that in EdkII variable driver implementation, Hardware Error Record type variable - // is stored with common variable in the same NV region. So the platform integrator should - // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of - // PcdFlashNvStorageVariableSize. - // - ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize)); - // // Get HOB variable store. // @@ -3162,6 +3402,7 @@ VariableCommonInitialize ( if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader); if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) { + FreePool (mVariableModuleGlobal); return EFI_OUT_OF_RESOURCES; } } else { @@ -3175,6 +3416,9 @@ VariableCommonInitialize ( ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize); if (VolatileVariableStore == NULL) { + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) { + FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase); + } FreePool (mVariableModuleGlobal); return EFI_OUT_OF_RESOURCES; } @@ -3186,7 +3430,6 @@ VariableCommonInitialize ( // mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore; mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore; - mVariableModuleGlobal->FvbInstance = NULL; CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid); VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize); @@ -3196,74 +3439,13 @@ VariableCommonInitialize ( VolatileVariableStore->Reserved1 = 0; // - // Get non-volatile variable store. - // - - TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); - if (TempVariableStoreHeader == 0) { - TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); - } - - // - // Check if the Firmware Volume is not corrupted - // - if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) || - (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) { - Status = EFI_VOLUME_CORRUPTED; - DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n")); - goto Done; - } - - VariableStoreBase = TempVariableStoreHeader + \ - (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength); - VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \ - (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength); - - mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; - VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; - if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { - Status = EFI_VOLUME_CORRUPTED; - DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n")); - goto Done; - } - ASSERT(VariableStoreHeader->Size == VariableStoreLength); - - // - // The max variable or hardware error variable size should be < variable store size. - // - ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength); - - // - // Parse non-volatile variable data and get last variable offset. - // - NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase); - while (IsValidVariableHeader (NextVariable)) { - VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER); - if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { - mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize); - } else { - mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize); - } - - NextVariable = GetNextVariablePtr (NextVariable); - } - - mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase; - - // - // Allocate runtime memory used for a memory copy of the FLASH region. - // Keep the memory and the FLASH in sync as updates occur + // Init non-volatile variable store. // - mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength); - if (mNvVariableCache == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Done; - } - CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength); - Status = EFI_SUCCESS; - -Done: + Status = InitNonVolatileVariableStore (); if (EFI_ERROR (Status)) { + if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) { + FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase); + } FreePool (mVariableModuleGlobal); FreePool (VolatileVariableStore); }