diff options
author | jljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524> | 2009-09-16 16:28:55 +0000 |
---|---|---|
committer | jljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524> | 2009-09-16 16:28:55 +0000 |
commit | 50944545795641de735586d4803f8fc38b43874e (patch) | |
tree | 03b1dff60958770ac8f3227f488f71c0fd637354 | |
parent | af2cfce391f3869c53c044dbaf2ce85aa3f5ebc8 (diff) | |
download | edk2-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.h | 35 | ||||
-rw-r--r-- | OvmfPkg/Library/NvVarsFileLib/FsAccess.c | 540 | ||||
-rw-r--r-- | OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.c | 53 | ||||
-rw-r--r-- | OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.h | 103 | ||||
-rw-r--r-- | OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.inf | 60 | ||||
-rw-r--r-- | OvmfPkg/Library/NvVarsFileLib/VarBuffer.c | 345 | ||||
-rw-r--r-- | OvmfPkg/OvmfPkg.dec | 7 |
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
|