mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 15:06:49 +00:00 
			
		
		
		
	 56d7640a53
			
		
	
	
		56d7640a53
		
	
	
	
	
		
			
			git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10439 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			541 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			541 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   File System Access for NvVarsFileLib
 | |
| 
 | |
|   Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
 | |
|   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 = (UINTN) 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,
 | |
|                (UINT32) VariableNameSize,
 | |
|                &VendorGuid,
 | |
|                VariableAttributes,
 | |
|                VariableData,
 | |
|                (UINT32) 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;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 |