Implement NvVarsFileLib to save and restore non-volatile variables using a file.
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 16 Sep 2009 16:28:55 +0000 (16:28 +0000)
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 16 Sep 2009 16:28:55 +0000 (16:28 +0000)
This library provides an interface where variables can be saved and restored
using a file in a file system accessible to the firmware.  It is expected
that a platform BDS library will use this library.  The platform BDS
implementation can decide which devices to connect and then to attempt to use
for saving and restoring NV variables.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9272 6f19259b-4bc3-4df7-8a09-765794883524

OvmfPkg/Include/Library/NvVarsFileLib.h [new file with mode: 0644]
OvmfPkg/Library/NvVarsFileLib/FsAccess.c [new file with mode: 0644]
OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.c [new file with mode: 0644]
OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.h [new file with mode: 0644]
OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.inf [new file with mode: 0644]
OvmfPkg/Library/NvVarsFileLib/VarBuffer.c [new file with mode: 0644]
OvmfPkg/OvmfPkg.dec

diff --git a/OvmfPkg/Include/Library/NvVarsFileLib.h b/OvmfPkg/Include/Library/NvVarsFileLib.h
new file mode 100644 (file)
index 0000000..63b1642
--- /dev/null
@@ -0,0 +1,35 @@
+/** @file\r
+  Provides functions to save and restore NV variables in a file.\r
+\r
+  Copyright (c) 2009, Intel Corporation<BR>\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __NV_VARS_FILE_LIB__\r
+#define __NV_VARS_FILE_LIB__\r
+\r
+/**\r
+  Attempts to connect the NvVarsFileLib to the specified file system.\r
+\r
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance\r
+\r
+  @return     The EFI_STATUS while attempting to connect the NvVarsFileLib\r
+              to the file system instance.\r
+  @retval     EFI_SUCCESS - The given file system was connected successfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ConnectNvVarsToFileSystem (\r
+  IN EFI_HANDLE    FsHandle\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/OvmfPkg/Library/NvVarsFileLib/FsAccess.c b/OvmfPkg/Library/NvVarsFileLib/FsAccess.c
new file mode 100644 (file)
index 0000000..cbae15a
--- /dev/null
@@ -0,0 +1,540 @@
+/** @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;
+
+}
+
+
diff --git a/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.c b/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.c
new file mode 100644 (file)
index 0000000..94e00e0
--- /dev/null
@@ -0,0 +1,53 @@
+/** @file
+  Save Non-Volatile Variables to a file system.
+
+  Copyright (c) 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/DebugLib.h>
+#include <Library/NvVarsFileLib.h>
+
+
+/**
+  Attempts to connect the NvVarsFileLib to the specified file system.
+
+  @param[in]  FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
+
+  @return     The EFI_STATUS while attempting to connect the NvVarsFileLib
+              to the file system instance.
+  @retval     EFI_SUCCESS - The given file system was connected successfully
+
+**/
+EFI_STATUS
+EFIAPI
+ConnectNvVarsToFileSystem (
+  IN EFI_HANDLE    FsHandle
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // We might fail to load the variable, since the file system initially
+  // will not have the NvVars file.
+  //
+  LoadNvVarsFromFs (FsHandle);
+
+  //
+  // We must be able to save the variables successfully to the file system
+  // to have connected successfully.
+  //
+  Status = SaveNvVarsToFs (FsHandle);
+
+  return Status;
+}
+
+
diff --git a/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.h b/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.h
new file mode 100644 (file)
index 0000000..6241dc8
--- /dev/null
@@ -0,0 +1,103 @@
+/** @file
+  Save Non-Volatile Variables to a file system.
+
+  Copyright (c) 2009, 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
+  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.
+
+**/
+
+#ifndef __NV_VARS_FILE_LIB_INSTANCE__
+#define __NV_VARS_FILE_LIB_INSTANCE__
+
+#include <Uefi.h>
+
+#include <Guid/FileInfo.h>
+
+#include <Protocol/SimpleFileSystem.h>
+
+#include <Library/BaseLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+/**
+  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
+  );
+
+
+/**
+  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
+  );
+
+
+/**
+  Examines the NvVars file contents, and updates variables based on it.
+
+  @param[in]  VarsBuffer - Buffer with NvVars data
+  @param[in]  VarsBufferSize - Size of VarsBuffer in bytes
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+EFI_STATUS
+SetVariablesFromBuffer (
+  IN VOID   *VarsBuffer,
+  IN UINTN  VarsBufferSize
+  );
+
+
+/**
+  Writes the variable into the file so it can be restored from
+  the file on future boots of the system.
+
+  @param[in]  File - The file to write to
+  @param[in]  Name - Variable name string
+  @param[in]  NameSize - Size of Name in bytes
+  @param[in]  Guid - GUID of variable
+  @param[in]  Attributes - Attributes of variable
+  @param[in]  Data - Buffer containing Data for variable
+  @param[in]  DataSize - Size of Data in bytes
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+EFI_STATUS
+PackVariableIntoFile (
+  IN EFI_FILE_HANDLE  File,
+  IN CHAR16           *Name,
+  IN UINT32           NameSize,
+  IN EFI_GUID         *Guid,
+  IN UINT32           Attributes,
+  IN VOID             *Data,
+  IN UINT32           DataSize
+  );
+
+#endif
+
diff --git a/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.inf b/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.inf
new file mode 100644 (file)
index 0000000..41f0549
--- /dev/null
@@ -0,0 +1,60 @@
+#/** @file\r
+#  NvVarsFileLib\r
+#\r
+#  This kibrary saves and restores non-volatile variables in a\r
+#  file within a file system.\r
+#\r
+#  Copyright (c) 2006 - 2009, Intel Corporation\r
+#\r
+#  All rights reserved. This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = NvVarsFileLib\r
+  FILE_GUID                      = 9172fe8b-9a36-40f8-bba5-5e57a44390bd\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = NvVarsFileLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+  FsAccess.c\r
+  NvVarsFileLib.c\r
+  VarBuffer.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  OvmfPkg/OvmfPkg.dec\r
+  ShellPkg/ShellPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  FileHandleLib\r
+  MemoryAllocationLib\r
+\r
+[Protocols]\r
+  gEfiSimpleFileSystemProtocolGuid              ## CONSUMES\r
+\r
+\r
+[Guids]\r
+  gEfiFileInfoGuid\r
+\r
+[Depex]\r
+  gEfiVariableWriteArchProtocolGuid\r
+\r
diff --git a/OvmfPkg/Library/NvVarsFileLib/VarBuffer.c b/OvmfPkg/Library/NvVarsFileLib/VarBuffer.c
new file mode 100644 (file)
index 0000000..4f32d27
--- /dev/null
@@ -0,0 +1,345 @@
+/** @file
+  File System Access
+
+  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>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+
+/**
+  Writes the variable into the file so it can be restored from
+  the file on future boots of the system.
+
+  @param[in]  File - The file to write to
+  @param[in]  Name - Variable name string
+  @param[in]  NameSize - Size of Name in bytes
+  @param[in]  Guid - GUID of variable
+  @param[in]  Attributes - Attributes of variable
+  @param[in]  Data - Buffer containing Data for variable
+  @param[in]  DataSize - Size of Data in bytes
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+EFI_STATUS
+PackVariableIntoFile (
+  IN EFI_FILE_HANDLE  File,
+  IN CHAR16           *Name,
+  IN UINT32           NameSize,
+  IN EFI_GUID         *Guid,
+  IN UINT32           Attributes,
+  IN VOID             *Data,
+  IN UINT32           DataSize
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       WriteSize;
+
+  WriteSize = sizeof (NameSize);
+  Status = FileHandleWrite (File, &WriteSize, &NameSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  WriteSize = NameSize;
+  Status = FileHandleWrite (File, &WriteSize, (VOID*) Name);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  WriteSize = sizeof (*Guid);
+  Status = FileHandleWrite (File, &WriteSize, (VOID*) Guid);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  WriteSize = sizeof (Attributes);
+  Status = FileHandleWrite (File, &WriteSize, &Attributes);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  WriteSize = sizeof (DataSize);
+  Status = FileHandleWrite (File, &WriteSize, &DataSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  WriteSize = DataSize;
+  Status = FileHandleWrite (File, &WriteSize, Data);
+
+  return Status;
+}
+
+
+/**
+  Unpacks the next variable from the NvVars file data
+
+  @param[in]  Buffer - Buffer pointing to the next variable instance
+                       On subsequent calls, the pointer should be incremented
+                       by the returned SizeUsed value.
+  @param[in]  MaxSize - Max allowable size for the variable data
+                        On subsequent calls, this should be decremented
+                        by the returned SizeUsed value.
+  @param[out] Name - Variable name string (address in Buffer)
+  @param[out] NameSize - Size of Name in bytes
+  @param[out] Guid - GUID of variable (address in Buffer)
+  @param[out] Attributes - Attributes of variable
+  @param[out] Data - Buffer containing Data for variable (address in Buffer)
+  @param[out] DataSize - Size of Data in bytes
+  @param[out] SizeUsed - Total size used for this variable instance in Buffer
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+EFI_STATUS
+UnpackVariableFromBuffer (
+  IN  VOID     *Buffer,
+  IN  UINTN    MaxSize,
+  OUT CHAR16   **Name,
+  OUT UINT32   *NameSize,
+  OUT EFI_GUID **Guid,
+  OUT UINT32   *Attributes,
+  OUT UINT32   *DataSize,
+  OUT VOID     **Data,
+  OUT UINTN    *SizeUsed
+  )
+{
+  UINT8  *BytePtr;
+  UINTN  Offset;
+
+  BytePtr = (UINT8*)Buffer;
+  Offset = 0;
+
+  *NameSize = *(UINT32*) (BytePtr + Offset);
+  Offset = Offset + sizeof (UINT32);
+
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Name = (CHAR16*) (BytePtr + Offset);
+  Offset = Offset + *(UINT32*)BytePtr;
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Guid = (EFI_GUID*) (BytePtr + Offset);
+  Offset = Offset + sizeof (EFI_GUID);
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Attributes = *(UINT32*) (BytePtr + Offset);
+  Offset = Offset + sizeof (UINT32);
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *DataSize = *(UINT32*) (BytePtr + Offset);
+  Offset = Offset + sizeof (UINT32);
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Data = (VOID*) (BytePtr + Offset);
+  Offset = Offset + *DataSize;
+  if (Offset > MaxSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *SizeUsed = Offset;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Examines the NvVars file contents, and updates variables based on it.
+
+  @param[in]  Buffer - Buffer with NvVars data
+  @param[in]  MaxSize - Size of Buffer in bytes
+  @param[in]  DryRun - If TRUE, then no variable modifications should be made
+                       (If TRUE, the Buffer is still parsed for validity.)
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+EFI_STATUS
+UnpackVariablesFromBuffer (
+  IN  VOID     *Buffer,
+  IN  UINTN    MaxSize,
+  IN  BOOLEAN  DryRun
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Count;
+  UINTN       TotalSizeUsed;
+  UINTN       SizeUsed;
+
+  CHAR16      *Name;
+  UINT32      NameSize;
+  CHAR16      *AlignedName;
+  UINT32      AlignedNameMaxSize;
+  EFI_GUID    *Guid;
+  UINT32      Attributes;
+  UINT32      DataSize;
+  VOID        *Data;
+
+  AlignedName = NULL;
+  AlignedNameMaxSize = 0;
+
+  for (
+    Status = EFI_SUCCESS, Count = 0, TotalSizeUsed = 0;
+    !EFI_ERROR (Status) && (TotalSizeUsed < MaxSize);
+    ) {
+    Status = UnpackVariableFromBuffer (
+               (VOID*) ((UINT8*) Buffer + TotalSizeUsed),
+               (MaxSize - TotalSizeUsed),
+               &Name,
+               &NameSize,
+               &Guid,
+               &Attributes,
+               &DataSize,
+               &Data,
+               &SizeUsed
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // We copy the name to a separately allocated buffer,
+    // to be sure it is 16-bit aligned.
+    //
+    if (NameSize > AlignedNameMaxSize) {
+      if (AlignedName != NULL) {
+        FreePool (AlignedName);
+      }
+      AlignedName = AllocatePool (NameSize);
+    }
+    if (AlignedName == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    CopyMem (AlignedName, Name, NameSize);
+
+    DEBUG ((
+      EFI_D_INFO,
+      "Unpacked variable %g:%s\n",
+      Guid,
+      AlignedName
+      ));
+
+    TotalSizeUsed = TotalSizeUsed + SizeUsed;
+
+    DEBUG ((
+      EFI_D_INFO,
+      "TotalSizeUsed(%d); MaxSize(%d)\n",
+      TotalSizeUsed,
+      MaxSize
+      ));
+
+    if (!DryRun) {
+      //
+      // Set the variable contents
+      //
+      gRT->SetVariable (
+             AlignedName,
+             Guid,
+             Attributes,
+             DataSize,
+             Data
+             );
+
+      Count++;
+
+      DEBUG ((
+        EFI_D_INFO,
+        "Restored variable %g:%s\n",
+        Guid,
+        AlignedName
+        ));
+    }
+
+  }
+
+  if (AlignedName != NULL) {
+    FreePool (AlignedName);
+  }
+
+  //
+  // Make sure the entire buffer was used, or else return an error
+  //
+  if (TotalSizeUsed != MaxSize) {
+    DEBUG ((
+      EFI_D_INFO,
+      "TotalSizeUsed(%d) != MaxSize(%d)\n",
+      TotalSizeUsed,
+      MaxSize
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Count > 0) {
+    DEBUG ((
+      EFI_D_INFO,
+      "Restored %d Variables\n",
+      Count
+      ));
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Examines the NvVars file contents, and updates variables based on it.
+
+  @param[in]  VarsBuffer - Buffer with NvVars data
+  @param[in]  VarsBufferSize - Size of VarsBuffer in bytes
+
+  @return     EFI_STATUS based on the success or failure of the operation
+
+**/
+EFI_STATUS
+SetVariablesFromBuffer (
+  IN VOID   *VarsBuffer,
+  IN UINTN  VarsBufferSize
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // First test to make sure the entire buffer is in a good state
+  //
+  Status = UnpackVariablesFromBuffer (VarsBuffer, VarsBufferSize, TRUE);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "NvVars buffer format was invalid\n"));
+    return Status;
+  }
+
+  //
+  // Now, actually restore the variables.
+  //
+  Status = UnpackVariablesFromBuffer (VarsBuffer, VarsBufferSize, FALSE);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return Status;
+}
+
index a2ad0a4a152757ff5efb3d0eb6c39f37e5817e4c..1c1741d27492fe24573214dda91baa58af71abc7 100644 (file)
@@ -19,6 +19,9 @@
   PACKAGE_GUID                   = 2daf5f34-50e5-4b9d-b8e3-5562334d87e5\r
   PACKAGE_VERSION                = 0.1\r
 \r
+[Includes]\r
+  Include\r
+\r
 [Guids.common]\r
   gUefiOvmfPkgTokenSpaceGuid      = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}\r
 \r
@@ -31,4 +34,8 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareBlockSize|0|UINT32|0x00001013\r
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase|0x0|UINT32|0x00001014\r
 \r
+[LibraryClasses]\r
+  ##  @libraryclass  Save and restore variables using a file\r
+  #\r
+  NvVarsFileLib|Include/Library/NvVarsFileLib.h\r
 \r