diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index d3df21819a..e8e19508cd 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -34,6 +34,7 @@ VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; /// /// Define a memory cache that improves the search performance for a variable. +/// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase. /// VARIABLE_STORE_HEADER *mNvVariableCache = NULL; @@ -273,7 +274,7 @@ UpdateVariableStore ( // // Check if the Data is Volatile. // - if (!Volatile) { + if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) { if (Fvb == NULL) { return EFI_UNSUPPORTED; } @@ -296,17 +297,30 @@ UpdateVariableStore ( // Data Pointer should point to the actual Address where data is to be // written. // - VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); - if (SetByIndex) { - DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; - } + if (Volatile) { + VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); + if (SetByIndex) { + DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + } - if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) { - return EFI_OUT_OF_RESOURCES; + if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // Emulated non-volatile variable mode. + // + if (SetByIndex) { + DataPtr += (UINTN) mNvVariableCache; + } + + if ((DataPtr + DataSize) > ((UINTN) mNvVariableCache + mNvVariableCache->Size)) { + return EFI_OUT_OF_RESOURCES; + } } // - // If Volatile Variable just do a simple mem copy. + // If Volatile/Emulated Non-volatile Variable just do a simple mem copy. // CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize); return EFI_SUCCESS; @@ -987,7 +1001,7 @@ Reclaim ( CommonUserVariableTotalSize = 0; HwErrVariableTotalSize = 0; - if (IsVolatile) { + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { // // Start Pointers for the variable. // @@ -1155,13 +1169,21 @@ Reclaim ( CurrPtr += NewVariableSize; } - if (IsVolatile) { + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { // - // If volatile variable store, just copy valid buffer. + // If volatile/emulated non-volatile variable store, just copy valid buffer. // SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff); CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer); *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer; + if (!IsVolatile) { + // + // Emulated non-volatile variable mode. + // + mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize; + mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize; + mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize; + } Status = EFI_SUCCESS; } else { // @@ -1200,7 +1222,7 @@ Reclaim ( } Done: - if (IsVolatile) { + if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) { FreePool (ValidBuffer); } else { // @@ -2147,7 +2169,7 @@ UpdateVariable ( BOOLEAN IsCommonUserVariable; AUTHENTICATED_VARIABLE_HEADER *AuthVariable; - if (mVariableModuleGlobal->FvbInstance == NULL) { + if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) { // // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed. // @@ -2566,86 +2588,107 @@ UpdateVariable ( } goto Done; } - // - // Four steps - // 1. Write variable header - // 2. Set variable state to header valid - // 3. Write variable data - // 4. Set variable state to valid - // - // - // Step 1: - // - Status = UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset, - (UINT32) GetVariableHeaderSize (), - (UINT8 *) NextVariable - ); - if (EFI_ERROR (Status)) { - goto Done; + if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) { + // + // Four steps + // 1. Write variable header + // 2. Set variable state to header valid + // 3. Write variable data + // 4. Set variable state to valid + // + // + // Step 1: + // + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset, + (UINT32) GetVariableHeaderSize (), + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Step 2: + // + NextVariable->State = VAR_HEADER_VALID_ONLY; + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State), + sizeof (UINT8), + &NextVariable->State + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Step 3: + // + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (), + (UINT32) (VarSize - GetVariableHeaderSize ()), + (UINT8 *) NextVariable + GetVariableHeaderSize () + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Step 4: + // + NextVariable->State = VAR_ADDED; + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State), + sizeof (UINT8), + &NextVariable->State + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Update the memory copy of Flash region. + // + CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize); + } else { + // + // Emulated non-volatile variable mode. + // + NextVariable->State = VAR_ADDED; + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset, + (UINT32) VarSize, + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } } - // - // Step 2: - // - NextVariable->State = VAR_HEADER_VALID_ONLY; - Status = UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State), - sizeof (UINT8), - &NextVariable->State - ); - - if (EFI_ERROR (Status)) { - goto Done; - } - // - // Step 3: - // - Status = UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (), - (UINT32) (VarSize - GetVariableHeaderSize ()), - (UINT8 *) NextVariable + GetVariableHeaderSize () - ); - - if (EFI_ERROR (Status)) { - goto Done; - } - // - // Step 4: - // - NextVariable->State = VAR_ADDED; - Status = UpdateVariableStore ( - &mVariableModuleGlobal->VariableGlobal, - FALSE, - TRUE, - Fvb, - mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State), - sizeof (UINT8), - &NextVariable->State - ); - - if (EFI_ERROR (Status)) { - goto Done; - } - - // - // Update the memory copy of Flash region. - // - CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize); - mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize); if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { @@ -3875,6 +3918,93 @@ InitRealNonVolatileVariableStore ( return EFI_SUCCESS; } +/** + Init emulated non-volatile variable store. + + @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +InitEmuNonVolatileVariableStore ( + EFI_PHYSICAL_ADDRESS *VariableStoreBase + ) +{ + VARIABLE_STORE_HEADER *VariableStore; + UINT32 VariableStoreLength; + BOOLEAN FullyInitializeStore; + UINT32 HwErrStorageSize; + + FullyInitializeStore = TRUE; + + VariableStoreLength = PcdGet32 (PcdVariableStoreSize); + ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength); + + // + // Allocate memory for variable store. + // + if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) { + VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength); + if (VariableStore == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // A memory location has been reserved for the NV variable store. Certain + // platforms may be able to preserve a memory range across system resets, + // thereby providing better NV variable emulation. + // + VariableStore = + (VARIABLE_STORE_HEADER *)(VOID*)(UINTN) + PcdGet64 (PcdEmuVariableNvStoreReserved); + if ((VariableStore->Size == VariableStoreLength) && + (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) || + CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) && + (VariableStore->Format == VARIABLE_STORE_FORMATTED) && + (VariableStore->State == VARIABLE_STORE_HEALTHY)) { + DEBUG(( + DEBUG_INFO, + "Variable Store reserved at %p appears to be valid\n", + VariableStore + )); + FullyInitializeStore = FALSE; + } + } + + if (FullyInitializeStore) { + SetMem (VariableStore, VariableStoreLength, 0xff); + // + // Use gEfiAuthenticatedVariableGuid for potential auth variable support. + // + CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid); + VariableStore->Size = VariableStoreLength; + VariableStore->Format = VARIABLE_STORE_FORMATTED; + VariableStore->State = VARIABLE_STORE_HEALTHY; + VariableStore->Reserved = 0; + VariableStore->Reserved1 = 0; + } + + *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore; + + HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize); + + // + // 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 the value of + // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)). + // + ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER))); + + mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize); + mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace; + mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace; + + return EFI_SUCCESS; +} + /** Init non-volatile variable store. @@ -3894,9 +4024,19 @@ InitNonVolatileVariableStore ( UINTN VariableSize; EFI_STATUS Status; - Status = InitRealNonVolatileVariableStore (&VariableStoreBase); - if (EFI_ERROR (Status)) { - return Status; + if (PcdGetBool (PcdEmuVariableNvModeEnable)) { + Status = InitEmuNonVolatileVariableStore (&VariableStoreBase); + if (EFI_ERROR (Status)) { + return Status; + } + mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE; + DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n")); + } else { + Status = InitRealNonVolatileVariableStore (&VariableStoreBase); + if (EFI_ERROR (Status)) { + return Status; + } + mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE; } mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h index d128d1a9c6..7a3a5f34de 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h @@ -92,6 +92,7 @@ typedef struct { UINT32 ReentrantState; BOOLEAN AuthFormat; BOOLEAN AuthSupport; + BOOLEAN EmuNvMode; } VARIABLE_GLOBAL; typedef struct { diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c index 521cb4ed24..adaf6ccb48 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c @@ -236,14 +236,16 @@ VariableClassAddressChangeEvent ( { UINTN Index; - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize); - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress); - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes); - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes); - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read); - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write); - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks); - EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance); + if (mVariableModuleGlobal->FvbInstance != NULL) { + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance); + } EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes); EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang); @@ -528,16 +530,23 @@ VariableServiceInitialize ( ); ASSERT_EFI_ERROR (Status); - // - // Register FtwNotificationEvent () notify function. - // - EfiCreateProtocolNotifyEvent ( - &gEfiFaultTolerantWriteProtocolGuid, - TPL_CALLBACK, - FtwNotificationEvent, - (VOID *)SystemTable, - &mFtwRegistration - ); + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { + // + // Register FtwNotificationEvent () notify function. + // + EfiCreateProtocolNotifyEvent ( + &gEfiFaultTolerantWriteProtocolGuid, + TPL_CALLBACK, + FtwNotificationEvent, + (VOID *)SystemTable, + &mFtwRegistration + ); + } else { + // + // Emulated non-volatile variable mode does not depend on FVB and FTW. + // + VariableWriteServiceInitializeDxe (); + } Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index 7ef8a97f5d..273067753c 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -9,7 +9,7 @@ # This external input must be validated carefully to avoid security issues such as # buffer overflow or integer overflow. # -# Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -131,6 +131,8 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## SOMETIMES_CONSUMES [FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable. diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c index e6734acdf2..3e35219d05 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c @@ -1012,17 +1012,24 @@ MmVariableServiceInitialize ( ); ASSERT_EFI_ERROR (Status); - // - // Register FtwNotificationEvent () notify function. - // - Status = gMmst->MmRegisterProtocolNotify ( - &gEfiSmmFaultTolerantWriteProtocolGuid, - SmmFtwNotificationEvent, - &SmmFtwRegistration - ); - ASSERT_EFI_ERROR (Status); + if (!PcdGetBool (PcdEmuVariableNvModeEnable)) { + // + // Register FtwNotificationEvent () notify function. + // + Status = gMmst->MmRegisterProtocolNotify ( + &gEfiSmmFaultTolerantWriteProtocolGuid, + SmmFtwNotificationEvent, + &SmmFtwRegistration + ); + ASSERT_EFI_ERROR (Status); - SmmFtwNotificationEvent (NULL, NULL, NULL); + SmmFtwNotificationEvent (NULL, NULL, NULL); + } else { + // + // Emulated non-volatile variable mode does not depend on FVB and FTW. + // + VariableWriteServiceInitializeSmm (); + } return EFI_SUCCESS; } diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf index ed7392cbcf..64ecb1a1b6 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf @@ -18,7 +18,7 @@ # may not be modified without authorization. If platform fails to protect these resources, # the authentication service provided in this driver will be broken, and the behavior is undefined. # -# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.
+# Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -134,6 +134,8 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxUserNvVariableSpaceSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdBoottimeReservedNvVariableSpaceSize ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdReclaimVariableSpaceAtEndOfDxe ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved ## SOMETIMES_CONSUMES [FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable.