\r
///\r
/// Define a memory cache that improves the search performance for a variable.\r
+/// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.\r
///\r
VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
\r
//\r
// Check if the Data is Volatile.\r
//\r
- if (!Volatile) {\r
+ if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
if (Fvb == NULL) {\r
return EFI_UNSUPPORTED;\r
}\r
// Data Pointer should point to the actual Address where data is to be\r
// written.\r
//\r
- VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
- if (SetByIndex) {\r
- DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
- }\r
+ if (Volatile) {\r
+ VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+ if (SetByIndex) {\r
+ DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
+ }\r
\r
- if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) {\r
- return EFI_OUT_OF_RESOURCES;\r
+ if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ //\r
+ // Emulated non-volatile variable mode.\r
+ //\r
+ if (SetByIndex) {\r
+ DataPtr += (UINTN) mNvVariableCache;\r
+ }\r
+\r
+ if ((DataPtr + DataSize) > ((UINTN) mNvVariableCache + mNvVariableCache->Size)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
}\r
\r
//\r
- // If Volatile Variable just do a simple mem copy.\r
+ // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.\r
//\r
CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
return EFI_SUCCESS;\r
CommonUserVariableTotalSize = 0;\r
HwErrVariableTotalSize = 0;\r
\r
- if (IsVolatile) {\r
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
//\r
// Start Pointers for the variable.\r
//\r
CurrPtr += NewVariableSize;\r
}\r
\r
- if (IsVolatile) {\r
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
//\r
- // If volatile variable store, just copy valid buffer.\r
+ // If volatile/emulated non-volatile variable store, just copy valid buffer.\r
//\r
SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer);\r
*LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;\r
+ if (!IsVolatile) {\r
+ //\r
+ // Emulated non-volatile variable mode.\r
+ //\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
+ }\r
Status = EFI_SUCCESS;\r
} else {\r
//\r
}\r
\r
Done:\r
- if (IsVolatile) {\r
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
FreePool (ValidBuffer);\r
} else {\r
//\r
BOOLEAN IsCommonUserVariable;\r
AUTHENTICATED_VARIABLE_HEADER *AuthVariable;\r
\r
- if (mVariableModuleGlobal->FvbInstance == NULL) {\r
+ if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
//\r
// The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.\r
//\r
}\r
goto Done;\r
}\r
- //\r
- // Four steps\r
- // 1. Write variable header\r
- // 2. Set variable state to header valid\r
- // 3. Write variable data\r
- // 4. Set variable state to valid\r
- //\r
- //\r
- // Step 1:\r
- //\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
- (UINT32) GetVariableHeaderSize (),\r
- (UINT8 *) NextVariable\r
- );\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
+ if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
+ //\r
+ // Four steps\r
+ // 1. Write variable header\r
+ // 2. Set variable state to header valid\r
+ // 3. Write variable data\r
+ // 4. Set variable state to valid\r
+ //\r
+ //\r
+ // Step 1:\r
+ //\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ (UINT32) GetVariableHeaderSize (),\r
+ (UINT8 *) NextVariable\r
+ );\r
\r
- //\r
- // Step 2:\r
- //\r
- NextVariable->State = VAR_HEADER_VALID_ONLY;\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
- sizeof (UINT8),\r
- &NextVariable->State\r
- );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- //\r
- // Step 3:\r
- //\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),\r
- (UINT32) (VarSize - GetVariableHeaderSize ()),\r
- (UINT8 *) NextVariable + GetVariableHeaderSize ()\r
- );\r
+ //\r
+ // Step 2:\r
+ //\r
+ NextVariable->State = VAR_HEADER_VALID_ONLY;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+ sizeof (UINT8),\r
+ &NextVariable->State\r
+ );\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- //\r
- // Step 4:\r
- //\r
- NextVariable->State = VAR_ADDED;\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
- sizeof (UINT8),\r
- &NextVariable->State\r
- );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Step 3:\r
+ //\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),\r
+ (UINT32) (VarSize - GetVariableHeaderSize ()),\r
+ (UINT8 *) NextVariable + GetVariableHeaderSize ()\r
+ );\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Step 4:\r
+ //\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+ sizeof (UINT8),\r
+ &NextVariable->State\r
+ );\r
\r
- //\r
- // Update the memory copy of Flash region.\r
- //\r
- CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Update the memory copy of Flash region.\r
+ //\r
+ CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);\r
+ } else {\r
+ //\r
+ // Emulated non-volatile variable mode.\r
+ //\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ (UINT32) VarSize,\r
+ (UINT8 *) NextVariable\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ }\r
\r
mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Init emulated non-volatile variable store.\r
+\r
+ @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.\r
+\r
+ @retval EFI_SUCCESS Function successfully executed.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+InitEmuNonVolatileVariableStore (\r
+ EFI_PHYSICAL_ADDRESS *VariableStoreBase\r
+ )\r
+{\r
+ VARIABLE_STORE_HEADER *VariableStore;\r
+ UINT32 VariableStoreLength;\r
+ BOOLEAN FullyInitializeStore;\r
+ UINT32 HwErrStorageSize;\r
+\r
+ FullyInitializeStore = TRUE;\r
+\r
+ VariableStoreLength = PcdGet32 (PcdVariableStoreSize);\r
+ ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+\r
+ //\r
+ // Allocate memory for variable store.\r
+ //\r
+ if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {\r
+ VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength);\r
+ if (VariableStore == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ //\r
+ // A memory location has been reserved for the NV variable store. Certain\r
+ // platforms may be able to preserve a memory range across system resets,\r
+ // thereby providing better NV variable emulation.\r
+ //\r
+ VariableStore =\r
+ (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)\r
+ PcdGet64 (PcdEmuVariableNvStoreReserved);\r
+ if ((VariableStore->Size == VariableStoreLength) &&\r
+ (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||\r
+ CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&\r
+ (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&\r
+ (VariableStore->State == VARIABLE_STORE_HEALTHY)) {\r
+ DEBUG((\r
+ DEBUG_INFO,\r
+ "Variable Store reserved at %p appears to be valid\n",\r
+ VariableStore\r
+ ));\r
+ FullyInitializeStore = FALSE;\r
+ }\r
+ }\r
+\r
+ if (FullyInitializeStore) {\r
+ SetMem (VariableStore, VariableStoreLength, 0xff);\r
+ //\r
+ // Use gEfiAuthenticatedVariableGuid for potential auth variable support.\r
+ //\r
+ CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
+ VariableStore->Size = VariableStoreLength;\r
+ VariableStore->Format = VARIABLE_STORE_FORMATTED;\r
+ VariableStore->State = VARIABLE_STORE_HEALTHY;\r
+ VariableStore->Reserved = 0;\r
+ VariableStore->Reserved1 = 0;\r
+ }\r
+\r
+ *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r
+\r
+ HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
+\r
+ //\r
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
+ // is stored with common variable in the same NV region. So the platform integrator should\r
+ // ensure that the value of PcdHwErrStorageSize is less than the value of\r
+ // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
+ //\r
+ ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
+\r
+ mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
+ mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
+ mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Init non-volatile variable store.\r
\r
UINTN VariableSize;\r
EFI_STATUS Status;\r
\r
- Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ if (PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
+ Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;\r
+ DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));\r
+ } else {\r
+ Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;\r
}\r
\r
mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
{\r
UINTN Index;\r
\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
- EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
+ if (mVariableModuleGlobal->FvbInstance != NULL) {\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
+ }\r
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);\r
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);\r
EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
- //\r
- // Register FtwNotificationEvent () notify function.\r
- //\r
- EfiCreateProtocolNotifyEvent (\r
- &gEfiFaultTolerantWriteProtocolGuid,\r
- TPL_CALLBACK,\r
- FtwNotificationEvent,\r
- (VOID *)SystemTable,\r
- &mFtwRegistration\r
- );\r
+ if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
+ //\r
+ // Register FtwNotificationEvent () notify function.\r
+ //\r
+ EfiCreateProtocolNotifyEvent (\r
+ &gEfiFaultTolerantWriteProtocolGuid,\r
+ TPL_CALLBACK,\r
+ FtwNotificationEvent,\r
+ (VOID *)SystemTable,\r
+ &mFtwRegistration\r
+ );\r
+ } else {\r
+ //\r
+ // Emulated non-volatile variable mode does not depend on FVB and FTW.\r
+ //\r
+ VariableWriteServiceInitializeDxe ();\r
+ }\r
\r
Status = gBS->CreateEventEx (\r
EVT_NOTIFY_SIGNAL,\r