From: jljusten Date: Wed, 16 Sep 2009 16:28:55 +0000 (+0000) Subject: Implement NvVarsFileLib to save and restore non-volatile variables using a file. X-Git-Tag: edk2-stable201903~17047 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=50944545795641de735586d4803f8fc38b43874e 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 --- diff --git a/OvmfPkg/Include/Library/NvVarsFileLib.h b/OvmfPkg/Include/Library/NvVarsFileLib.h new file mode 100644 index 0000000000..63b1642f54 --- /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
+ 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 0000000000..cbae15afad --- /dev/null +++ b/OvmfPkg/Library/NvVarsFileLib/FsAccess.c @@ -0,0 +1,540 @@ +/** @file + File System Access for NvVarsFileLib + + Copyright (c) 2004 - 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. + +**/ + +#include "NvVarsFileLib.h" + +#include +#include +#include + + +/** + 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 0000000000..94e00e0bdb --- /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.
+ 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 +#include + + +/** + 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 0000000000..6241dc8842 --- /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 + +#include + +#include + +#include +#include +#include +#include +#include + +/** + 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 0000000000..41f0549abc --- /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 0000000000..4f32d27db8 --- /dev/null +++ b/OvmfPkg/Library/NvVarsFileLib/VarBuffer.c @@ -0,0 +1,345 @@ +/** @file + File System Access + + Copyright (c) 2004 - 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. + +**/ + +#include "NvVarsFileLib.h" + +#include +#include +#include +#include + + +/** + 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 a2ad0a4a15..1c1741d274 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