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
This commit is contained in:
345
OvmfPkg/Library/NvVarsFileLib/VarBuffer.c
Normal file
345
OvmfPkg/Library/NvVarsFileLib/VarBuffer.c
Normal file
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user