summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2009-09-16 16:28:55 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2009-09-16 16:28:55 +0000
commit50944545795641de735586d4803f8fc38b43874e (patch)
tree03b1dff60958770ac8f3227f488f71c0fd637354
parentaf2cfce391f3869c53c044dbaf2ce85aa3f5ebc8 (diff)
downloadedk2-50944545795641de735586d4803f8fc38b43874e.zip
edk2-50944545795641de735586d4803f8fc38b43874e.tar.gz
edk2-50944545795641de735586d4803f8fc38b43874e.tar.bz2
Implement NvVarsFileLib to save and restore non-volatile variables using a file.
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
-rw-r--r--OvmfPkg/Include/Library/NvVarsFileLib.h35
-rw-r--r--OvmfPkg/Library/NvVarsFileLib/FsAccess.c540
-rw-r--r--OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.c53
-rw-r--r--OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.h103
-rw-r--r--OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.inf60
-rw-r--r--OvmfPkg/Library/NvVarsFileLib/VarBuffer.c345
-rw-r--r--OvmfPkg/OvmfPkg.dec7
7 files changed, 1143 insertions, 0 deletions
diff --git a/OvmfPkg/Include/Library/NvVarsFileLib.h b/OvmfPkg/Include/Library/NvVarsFileLib.h
new file mode 100644
index 0000000..63b1642
--- /dev/null
+++ b/OvmfPkg/Include/Library/NvVarsFileLib.h
@@ -0,0 +1,35 @@
+/** @file
+ Provides functions to save and restore NV variables in a file.
+
+ 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.
+
+**/
+
+#ifndef __NV_VARS_FILE_LIB__
+#define __NV_VARS_FILE_LIB__
+
+/**
+ 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
+ );
+
+#endif
+
diff --git a/OvmfPkg/Library/NvVarsFileLib/FsAccess.c b/OvmfPkg/Library/NvVarsFileLib/FsAccess.c
new file mode 100644
index 0000000..cbae15a
--- /dev/null
+++ b/OvmfPkg/Library/NvVarsFileLib/FsAccess.c
@@ -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
index 0000000..94e00e0
--- /dev/null
+++ b/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.c
@@ -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
index 0000000..6241dc8
--- /dev/null
+++ b/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.h
@@ -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
index 0000000..41f0549
--- /dev/null
+++ b/OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.inf
@@ -0,0 +1,60 @@
+#/** @file
+# NvVarsFileLib
+#
+# This kibrary saves and restores non-volatile variables in a
+# file within a file system.
+#
+# Copyright (c) 2006 - 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.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = NvVarsFileLib
+ FILE_GUID = 9172fe8b-9a36-40f8-bba5-5e57a44390bd
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NvVarsFileLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ FsAccess.c
+ NvVarsFileLib.c
+ VarBuffer.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ FileHandleLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## CONSUMES
+
+
+[Guids]
+ gEfiFileInfoGuid
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid
+
diff --git a/OvmfPkg/Library/NvVarsFileLib/VarBuffer.c b/OvmfPkg/Library/NvVarsFileLib/VarBuffer.c
new file mode 100644
index 0000000..4f32d27
--- /dev/null
+++ b/OvmfPkg/Library/NvVarsFileLib/VarBuffer.c
@@ -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;
+}
+
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index a2ad0a4..1c1741d 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -19,6 +19,9 @@
PACKAGE_GUID = 2daf5f34-50e5-4b9d-b8e3-5562334d87e5
PACKAGE_VERSION = 0.1
+[Includes]
+ Include
+
[Guids.common]
gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
@@ -31,4 +34,8 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareBlockSize|0|UINT32|0x00001013
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase|0x0|UINT32|0x00001014
+[LibraryClasses]
+ ## @libraryclass Save and restore variables using a file
+ #
+ NvVarsFileLib|Include/Library/NvVarsFileLib.h