-/** @file
- File System Access for NvVarsFileLib
-
- Copyright (c) 2004 - 2009, Intel Corporation. <BR>
- 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
- http://opensource.org/licenses/bsd-license.php
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "NvVarsFileLib.h"
-
-#include <Library/BaseMemoryLib.h>
-#include <Library/DebugLib.h>
-#include <Library/MemoryAllocationLib.h>
-
-
-/**
- Open the NvVars file for reading or writing
-
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
- @param[in] ReadingFile - TRUE: open the file for reading. FALSE: writing
- @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated
- with the opened NvVars file.
-
- @return EFI_SUCCESS if the file was opened
-
-**/
-EFI_STATUS
-GetNvVarsFile (
- IN EFI_HANDLE FsHandle,
- IN BOOLEAN ReadingFile,
- OUT EFI_FILE_HANDLE *NvVarsFile
- )
-{
- EFI_STATUS Status;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
- EFI_FILE_HANDLE Root;
-
- //
- // Get the FileSystem protocol on that handle
- //
- Status = gBS->HandleProtocol (
- FsHandle,
- &gEfiSimpleFileSystemProtocolGuid,
- (VOID **)&Fs
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Get the volume (the root directory)
- //
- Status = Fs->OpenVolume (Fs, &Root);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Attempt to open the NvVars file in the root directory
- //
- Status = Root->Open (
- Root,
- NvVarsFile,
- L"NvVars",
- ReadingFile ?
- EFI_FILE_MODE_READ :
- (
- EFI_FILE_MODE_CREATE |
- EFI_FILE_MODE_READ |
- EFI_FILE_MODE_WRITE
- ),
- 0
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- return Status;
-}
-
-
-/**
- Open the NvVars file for reading or writing
-
- @param[in] File - The file to inspect
- @param[out] Exists - Returns whether the file exists
- @param[out] Size - Returns the size of the file
- (0 if the file does not exist)
-
-**/
-VOID
-NvVarsFileReadCheckup (
- IN EFI_FILE_HANDLE File,
- OUT BOOLEAN *Exists,
- OUT UINTN *Size
- )
-{
- EFI_FILE_INFO *FileInfo;
-
- *Exists = FALSE;
- *Size = 0;
-
- FileInfo = FileHandleGetInfo (File);
- if (FileInfo == NULL) {
- return;
- }
-
- if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
- FreePool (FileInfo);
- return;
- }
-
- *Exists = TRUE;
- *Size = FileInfo->FileSize;
-
- FreePool (FileInfo);
-}
-
-
-/**
- Open the NvVars file for reading or writing
-
- @param[in] File - The file to inspect
- @param[out] Exists - Returns whether the file exists
- @param[out] Size - Returns the size of the file
- (0 if the file does not exist)
-
-**/
-EFI_STATUS
-FileHandleEmpty (
- IN EFI_FILE_HANDLE File
- )
-{
- EFI_STATUS Status;
- EFI_FILE_INFO *FileInfo;
-
- //
- // Retrieve the FileInfo structure
- //
- FileInfo = FileHandleGetInfo (File);
- if (FileInfo == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // If the path is a directory, then return an error
- //
- if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
- FreePool (FileInfo);
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // If the file size is already 0, then it is empty, so
- // we can return success.
- //
- if (FileInfo->FileSize == 0) {
- FreePool (FileInfo);
- return EFI_SUCCESS;
- }
-
- //
- // Set the file size to 0.
- //
- FileInfo->FileSize = 0;
- Status = FileHandleSetInfo (File, FileInfo);
-
- FreePool (FileInfo);
-
- return Status;
-}
-
-
-/**
- Reads a file to a newly allocated buffer
-
- @param[in] File - The file to read
- @param[in] ReadSize - The size of data to read from the file
-
- @return Pointer to buffer allocated to hold the file
- contents. NULL if an error occured.
-
-**/
-VOID*
-FileHandleReadToNewBuffer (
- IN EFI_FILE_HANDLE FileHandle,
- IN UINTN ReadSize
- )
-{
- EFI_STATUS Status;
- UINTN ActualReadSize;
- VOID *FileContents;
-
- ActualReadSize = ReadSize;
- FileContents = AllocatePool (ReadSize);
- if (FileContents != NULL) {
- Status = FileHandleRead (
- FileHandle,
- &ReadSize,
- FileContents
- );
- if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {
- FreePool (FileContents);
- return NULL;
- }
- }
-
- return FileContents;
-}
-
-
-/**
- Reads the contents of the NvVars file on the file system
-
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
-
- @return EFI_STATUS based on the success or failure of the file read
-
-**/
-EFI_STATUS
-ReadNvVarsFile (
- IN EFI_HANDLE FsHandle
- )
-{
- EFI_STATUS Status;
- EFI_FILE_HANDLE File;
- UINTN FileSize;
- BOOLEAN FileExists;
- VOID *FileContents;
-
- Status = GetNvVarsFile (FsHandle, TRUE, &File);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));
- return Status;
- }
-
- NvVarsFileReadCheckup (File, &FileExists, &FileSize);
- if (FileSize == 0) {
- FileHandleClose (File);
- return EFI_UNSUPPORTED;
- }
-
- FileContents = FileHandleReadToNewBuffer (File, FileSize);
- if (FileContents == NULL) {
- FileHandleClose (File);
- return EFI_UNSUPPORTED;
- }
-
- DEBUG ((
- EFI_D_INFO,
- "FsAccess.c: Read %d bytes from NV Variables file\n",
- FileSize
- ));
-
- Status = SetVariablesFromBuffer (FileContents, FileSize);
-
- FreePool (FileContents);
- FileHandleClose (File);
-
- return Status;
-}
-
-
-/**
- Loads the non-volatile variables from the NvVars file on the
- given file system.
-
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
-
- @return EFI_STATUS based on the success or failure of load operation
-
-**/
-EFI_STATUS
-LoadNvVarsFromFs (
- EFI_HANDLE FsHandle
- )
-{
- EFI_STATUS Status;
- BOOLEAN VarData;
- UINTN Size;
-
- DEBUG ((EFI_D_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));
-
- //
- // We write a variable to indicate we've already loaded the
- // variable data. If it is found, we skip the loading.
- //
- // This is relevent if the non-volatile variable have been
- // able to survive a reboot operation. In that case, we don't
- // want to re-load the file as it would overwrite newer changes
- // made to the variables.
- //
- Size = sizeof (VarData);
- VarData = TRUE;
- Status = gRT->GetVariable (
- L"NvVars",
- &gEfiSimpleFileSystemProtocolGuid,
- NULL,
- &Size,
- (VOID*) &VarData
- );
- if (Status == EFI_SUCCESS) {
- DEBUG ((EFI_D_INFO, "NV Variables were already loaded\n"));
- return EFI_ALREADY_STARTED;
- }
-
- //
- // Attempt to restore the variables from the NvVars file.
- //
- Status = ReadNvVarsFile (FsHandle);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "Error while restoring NV variable data\n"));
- return Status;
- }
-
- //
- // Write a variable to indicate we've already loaded the
- // variable data. If it is found, we skip the loading on
- // subsequent attempts.
- //
- Size = sizeof (VarData);
- VarData = TRUE;
- gRT->SetVariable (
- L"NvVars",
- &gEfiSimpleFileSystemProtocolGuid,
- EFI_VARIABLE_NON_VOLATILE |
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS,
- Size,
- (VOID*) &VarData
- );
-
- DEBUG ((
- EFI_D_INFO,
- "FsAccess.c: Read NV Variables file (size=%d)\n",
- Size
- ));
-
- return Status;
-}
-
-
-/**
- Saves the non-volatile variables into the NvVars file on the
- given file system.
-
- @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
-
- @return EFI_STATUS based on the success or failure of load operation
-
-**/
-EFI_STATUS
-SaveNvVarsToFs (
- EFI_HANDLE FsHandle
- )
-{
- EFI_STATUS Status;
- EFI_FILE_HANDLE File;
- UINTN VariableNameBufferSize;
- UINTN VariableNameSize;
- CHAR16 *VariableName;
- EFI_GUID VendorGuid;
- UINTN VariableDataBufferSize;
- UINTN VariableDataSize;
- VOID *VariableData;
- UINT32 VariableAttributes;
- VOID *NewBuffer;
-
- //
- // Open the NvVars file for writing.
- //
- Status = GetNvVarsFile (FsHandle, FALSE, &File);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));
- return Status;
- }
-
- //
- // Empty the starting file contents.
- //
- Status = FileHandleEmpty (File);
- if (EFI_ERROR (Status)) {
- FileHandleClose (File);
- return Status;
- }
-
- //
- // Initialize the variable name and data buffer variables.
- //
- VariableNameBufferSize = sizeof (CHAR16);
- VariableName = AllocateZeroPool (VariableNameBufferSize);
-
- VariableDataBufferSize = 0;
- VariableData = NULL;
-
- for (;;) {
- //
- // Get the next variable name and guid
- //
- VariableNameSize = VariableNameBufferSize;
- Status = gRT->GetNextVariableName (
- &VariableNameSize,
- VariableName,
- &VendorGuid
- );
- if (Status == EFI_BUFFER_TOO_SMALL) {
- //
- // The currently allocated VariableName buffer is too small,
- // so we allocate a larger buffer, and copy the old buffer
- // to it.
- //
- NewBuffer = AllocatePool (VariableNameSize);
- if (NewBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- break;
- }
- CopyMem (NewBuffer, VariableName, VariableNameBufferSize);
- if (VariableName != NULL) {
- FreePool (VariableName);
- }
- VariableName = NewBuffer;
- VariableNameBufferSize = VariableNameSize;
-
- //
- // Try to get the next variable name again with the larger buffer.
- //
- Status = gRT->GetNextVariableName (
- &VariableNameSize,
- VariableName,
- &VendorGuid
- );
- }
-
- if (EFI_ERROR (Status)) {
- if (Status == EFI_NOT_FOUND) {
- Status = EFI_SUCCESS;
- }
- break;
- }
-
- //
- // Get the variable data and attributes
- //
- VariableDataSize = VariableDataBufferSize;
- Status = gRT->GetVariable (
- VariableName,
- &VendorGuid,
- &VariableAttributes,
- &VariableDataSize,
- VariableData
- );
- if (Status == EFI_BUFFER_TOO_SMALL) {
- //
- // The currently allocated VariableData buffer is too small,
- // so we allocate a larger buffer.
- //
- if (VariableDataBufferSize != 0) {
- FreePool (VariableData);
- VariableData = NULL;
- VariableDataBufferSize = 0;
- }
- VariableData = AllocatePool (VariableDataSize);
- if (VariableData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- break;
- }
- VariableDataBufferSize = VariableDataSize;
-
- //
- // Try to read the variable again with the larger buffer.
- //
- Status = gRT->GetVariable (
- VariableName,
- &VendorGuid,
- &VariableAttributes,
- &VariableDataSize,
- VariableData
- );
- }
- if (EFI_ERROR (Status)) {
- break;
- }
-
- //
- // Skip volatile variables. We only preserve non-volatile variables.
- //
- if ((VariableAttributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
- continue;
- }
-
- DEBUG ((
- EFI_D_INFO,
- "Saving variable %g:%s to file\n",
- &VendorGuid,
- VariableName
- ));
-
- //
- // Write the variable information out to the file
- //
- Status = PackVariableIntoFile (
- File,
- VariableName,
- VariableNameSize,
- &VendorGuid,
- VariableAttributes,
- VariableData,
- VariableDataSize
- );
- if (EFI_ERROR (Status)) {
- break;
- }
-
- }
-
- if (VariableName != NULL) {
- FreePool (VariableName);
- }
-
- if (VariableData != NULL) {
- FreePool (VariableData);
- }
-
- FileHandleClose (File);
-
- if (!EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "Saved NV Variables to NvVars file\n"));
- }
-
- return Status;
-
-}
-
-
+/** @file\r
+ File System Access for NvVarsFileLib\r
+\r
+ Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "NvVarsFileLib.h"\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+/**\r
+ Open the NvVars file for reading or writing\r
+\r
+ @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
+ @param[in] ReadingFile - TRUE: open the file for reading. FALSE: writing\r
+ @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated\r
+ with the opened NvVars file.\r
+\r
+ @return EFI_SUCCESS if the file was opened\r
+\r
+**/\r
+EFI_STATUS\r
+GetNvVarsFile (\r
+ IN EFI_HANDLE FsHandle,\r
+ IN BOOLEAN ReadingFile,\r
+ OUT EFI_FILE_HANDLE *NvVarsFile\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
+ EFI_FILE_HANDLE Root;\r
+\r
+ //\r
+ // Get the FileSystem protocol on that handle\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ FsHandle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ (VOID **)&Fs\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the volume (the root directory)\r
+ //\r
+ Status = Fs->OpenVolume (Fs, &Root);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Attempt to open the NvVars file in the root directory\r
+ //\r
+ Status = Root->Open (\r
+ Root,\r
+ NvVarsFile,\r
+ L"NvVars",\r
+ ReadingFile ?\r
+ EFI_FILE_MODE_READ :\r
+ (\r
+ EFI_FILE_MODE_CREATE |\r
+ EFI_FILE_MODE_READ |\r
+ EFI_FILE_MODE_WRITE\r
+ ),\r
+ 0\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Open the NvVars file for reading or writing\r
+\r
+ @param[in] File - The file to inspect\r
+ @param[out] Exists - Returns whether the file exists\r
+ @param[out] Size - Returns the size of the file\r
+ (0 if the file does not exist)\r
+\r
+**/\r
+VOID\r
+NvVarsFileReadCheckup (\r
+ IN EFI_FILE_HANDLE File,\r
+ OUT BOOLEAN *Exists,\r
+ OUT UINTN *Size\r
+ )\r
+{\r
+ EFI_FILE_INFO *FileInfo;\r
+\r
+ *Exists = FALSE;\r
+ *Size = 0;\r
+\r
+ FileInfo = FileHandleGetInfo (File);\r
+ if (FileInfo == NULL) {\r
+ return;\r
+ }\r
+\r
+ if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {\r
+ FreePool (FileInfo);\r
+ return;\r
+ }\r
+\r
+ *Exists = TRUE;\r
+ *Size = (UINTN)FileInfo->FileSize;\r
+\r
+ FreePool (FileInfo);\r
+}\r
+\r
+/**\r
+ Open the NvVars file for reading or writing\r
+\r
+ @param[in] File - The file to inspect\r
+ @param[out] Exists - Returns whether the file exists\r
+ @param[out] Size - Returns the size of the file\r
+ (0 if the file does not exist)\r
+\r
+**/\r
+EFI_STATUS\r
+FileHandleEmpty (\r
+ IN EFI_FILE_HANDLE File\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_INFO *FileInfo;\r
+\r
+ //\r
+ // Retrieve the FileInfo structure\r
+ //\r
+ FileInfo = FileHandleGetInfo (File);\r
+ if (FileInfo == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If the path is a directory, then return an error\r
+ //\r
+ if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {\r
+ FreePool (FileInfo);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If the file size is already 0, then it is empty, so\r
+ // we can return success.\r
+ //\r
+ if (FileInfo->FileSize == 0) {\r
+ FreePool (FileInfo);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Set the file size to 0.\r
+ //\r
+ FileInfo->FileSize = 0;\r
+ Status = FileHandleSetInfo (File, FileInfo);\r
+\r
+ FreePool (FileInfo);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Reads a file to a newly allocated buffer\r
+\r
+ @param[in] File - The file to read\r
+ @param[in] ReadSize - The size of data to read from the file\r
+\r
+ @return Pointer to buffer allocated to hold the file\r
+ contents. NULL if an error occurred.\r
+\r
+**/\r
+VOID *\r
+FileHandleReadToNewBuffer (\r
+ IN EFI_FILE_HANDLE FileHandle,\r
+ IN UINTN ReadSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN ActualReadSize;\r
+ VOID *FileContents;\r
+\r
+ ActualReadSize = ReadSize;\r
+ FileContents = AllocatePool (ReadSize);\r
+ if (FileContents != NULL) {\r
+ Status = FileHandleRead (\r
+ FileHandle,\r
+ &ReadSize,\r
+ FileContents\r
+ );\r
+ if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {\r
+ FreePool (FileContents);\r
+ return NULL;\r
+ }\r
+ }\r
+\r
+ return FileContents;\r
+}\r
+\r
+/**\r
+ Reads the contents of the NvVars file on the file system\r
+\r
+ @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
+\r
+ @return EFI_STATUS based on the success or failure of the file read\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNvVarsFile (\r
+ IN EFI_HANDLE FsHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE File;\r
+ UINTN FileSize;\r
+ BOOLEAN FileExists;\r
+ VOID *FileContents;\r
+ EFI_HANDLE SerializedVariables;\r
+\r
+ Status = GetNvVarsFile (FsHandle, TRUE, &File);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));\r
+ return Status;\r
+ }\r
+\r
+ NvVarsFileReadCheckup (File, &FileExists, &FileSize);\r
+ if (FileSize == 0) {\r
+ FileHandleClose (File);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FileContents = FileHandleReadToNewBuffer (File, FileSize);\r
+ if (FileContents == NULL) {\r
+ FileHandleClose (File);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "FsAccess.c: Read %Lu bytes from NV Variables file\n",\r
+ (UINT64)FileSize\r
+ ));\r
+\r
+ Status = SerializeVariablesNewInstanceFromBuffer (\r
+ &SerializedVariables,\r
+ FileContents,\r
+ FileSize\r
+ );\r
+ if (!RETURN_ERROR (Status)) {\r
+ Status = SerializeVariablesSetSerializedVariables (SerializedVariables);\r
+ }\r
+\r
+ FreePool (FileContents);\r
+ FileHandleClose (File);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Writes a variable to indicate that the NV variables\r
+ have been loaded from the file system.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SetNvVarsVariable (\r
+ VOID\r
+ )\r
+{\r
+ BOOLEAN VarData;\r
+ UINTN Size;\r
+\r
+ //\r
+ // Write a variable to indicate we've already loaded the\r
+ // variable data. If it is found, we skip the loading on\r
+ // subsequent attempts.\r
+ //\r
+ Size = sizeof (VarData);\r
+ VarData = TRUE;\r
+ gRT->SetVariable (\r
+ L"NvVars",\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ EFI_VARIABLE_NON_VOLATILE |\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
+ EFI_VARIABLE_RUNTIME_ACCESS,\r
+ Size,\r
+ (VOID *)&VarData\r
+ );\r
+}\r
+\r
+/**\r
+ Loads the non-volatile variables from the NvVars file on the\r
+ given file system.\r
+\r
+ @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
+\r
+ @return EFI_STATUS based on the success or failure of load operation\r
+\r
+**/\r
+EFI_STATUS\r
+LoadNvVarsFromFs (\r
+ EFI_HANDLE FsHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN VarData;\r
+ UINTN Size;\r
+\r
+ DEBUG ((DEBUG_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));\r
+\r
+ //\r
+ // We write a variable to indicate we've already loaded the\r
+ // variable data. If it is found, we skip the loading.\r
+ //\r
+ // This is relevant if the non-volatile variable have been\r
+ // able to survive a reboot operation. In that case, we don't\r
+ // want to re-load the file as it would overwrite newer changes\r
+ // made to the variables.\r
+ //\r
+ Size = sizeof (VarData);\r
+ VarData = TRUE;\r
+ Status = gRT->GetVariable (\r
+ L"NvVars",\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ NULL,\r
+ &Size,\r
+ (VOID *)&VarData\r
+ );\r
+ if (Status == EFI_SUCCESS) {\r
+ DEBUG ((DEBUG_INFO, "NV Variables were already loaded\n"));\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ //\r
+ // Attempt to restore the variables from the NvVars file.\r
+ //\r
+ Status = ReadNvVarsFile (FsHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "Error while restoring NV variable data\n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Write a variable to indicate we've already loaded the\r
+ // variable data. If it is found, we skip the loading on\r
+ // subsequent attempts.\r
+ //\r
+ SetNvVarsVariable ();\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "FsAccess.c: Read NV Variables file (size=%Lu)\n",\r
+ (UINT64)Size\r
+ ));\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+RETURN_STATUS\r
+EFIAPI\r
+IterateVariablesCallbackAddAllNvVariables (\r
+ IN VOID *Context,\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ EFI_HANDLE Instance;\r
+\r
+ Instance = (EFI_HANDLE)Context;\r
+\r
+ //\r
+ // Only save non-volatile variables\r
+ //\r
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+\r
+ return SerializeVariablesAddVariable (\r
+ Instance,\r
+ VariableName,\r
+ VendorGuid,\r
+ Attributes,\r
+ DataSize,\r
+ Data\r
+ );\r
+}\r
+\r
+/**\r
+ Saves the non-volatile variables into the NvVars file on the\r
+ given file system.\r
+\r
+ @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
+\r
+ @return EFI_STATUS based on the success or failure of load operation\r
+\r
+**/\r
+EFI_STATUS\r
+SaveNvVarsToFs (\r
+ EFI_HANDLE FsHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_HANDLE File;\r
+ UINTN WriteSize;\r
+ UINTN VariableDataSize;\r
+ VOID *VariableData;\r
+ EFI_HANDLE SerializedVariables;\r
+\r
+ SerializedVariables = NULL;\r
+\r
+ Status = SerializeVariablesNewInstance (&SerializedVariables);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SerializeVariablesIterateSystemVariables (\r
+ IterateVariablesCallbackAddAllNvVariables,\r
+ (VOID *)SerializedVariables\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ VariableData = NULL;\r
+ VariableDataSize = 0;\r
+ Status = SerializeVariablesToBuffer (\r
+ SerializedVariables,\r
+ NULL,\r
+ &VariableDataSize\r
+ );\r
+ if (Status == RETURN_BUFFER_TOO_SMALL) {\r
+ VariableData = AllocatePool (VariableDataSize);\r
+ if (VariableData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ Status = SerializeVariablesToBuffer (\r
+ SerializedVariables,\r
+ VariableData,\r
+ &VariableDataSize\r
+ );\r
+ }\r
+ }\r
+\r
+ SerializeVariablesFreeInstance (SerializedVariables);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open the NvVars file for writing.\r
+ //\r
+ Status = GetNvVarsFile (FsHandle, FALSE, &File);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Empty the starting file contents.\r
+ //\r
+ Status = FileHandleEmpty (File);\r
+ if (EFI_ERROR (Status)) {\r
+ FileHandleClose (File);\r
+ return Status;\r
+ }\r
+\r
+ WriteSize = VariableDataSize;\r
+ Status = FileHandleWrite (File, &WriteSize, VariableData);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FileHandleClose (File);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Write a variable to indicate we've already loaded the\r
+ // variable data. If it is found, we skip the loading on\r
+ // subsequent attempts.\r
+ //\r
+ SetNvVarsVariable ();\r
+\r
+ DEBUG ((DEBUG_INFO, "Saved NV Variables to NvVars file\n"));\r
+ }\r
+\r
+ return Status;\r
+}\r