2019-09-03 11:58:42 +02:00
|
|
|
/** @file
|
|
|
|
Utility routines used by boot maintenance modules.
|
|
|
|
|
|
|
|
Copyright (c) 2004 - 2014, 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 "BootMaint.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
Function opens and returns a file handle to the root directory of a volume.
|
|
|
|
|
|
|
|
@param DeviceHandle A handle for a device
|
|
|
|
|
|
|
|
@return A valid file handle or NULL is returned
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_FILE_HANDLE
|
|
|
|
EfiLibOpenRoot (
|
|
|
|
IN EFI_HANDLE DeviceHandle
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
|
|
|
|
EFI_FILE_HANDLE File;
|
|
|
|
|
|
|
|
File = NULL;
|
|
|
|
|
|
|
|
//
|
|
|
|
// File the file system interface to the device
|
|
|
|
//
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
DeviceHandle,
|
|
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
|
|
(VOID **) &Volume
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Open the root directory of the volume
|
|
|
|
//
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2019-09-03 11:58:42 +02:00
|
|
|
Status = Volume->OpenVolume (
|
|
|
|
Volume,
|
|
|
|
&File
|
|
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Done
|
|
|
|
//
|
2020-04-23 11:08:10 +02:00
|
|
|
return EFI_ERROR(Status) ? NULL : File;
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
Helper function called as part of the code needed
|
|
|
|
to allocate the proper sized buffer for various
|
|
|
|
EFI interfaces.
|
|
|
|
|
|
|
|
|
|
|
|
@param Status Current status
|
|
|
|
@param Buffer Current allocated buffer, or NULL
|
|
|
|
@param BufferSize Current buffer size needed
|
|
|
|
|
|
|
|
@retval TRUE if the buffer was reallocated and the caller
|
|
|
|
should try the API again.
|
|
|
|
@retval FALSE The caller should not call this function again.
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
EfiGrowBuffer (
|
|
|
|
IN OUT EFI_STATUS *Status,
|
|
|
|
IN OUT VOID **Buffer,
|
|
|
|
IN UINTN BufferSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
BOOLEAN TryAgain;
|
|
|
|
|
|
|
|
//
|
|
|
|
// If this is an initial request, buffer will be null with a new buffer size
|
|
|
|
//
|
|
|
|
if ((*Buffer == NULL) && (BufferSize != 0)) {
|
|
|
|
*Status = EFI_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// If the status code is "buffer too small", resize the buffer
|
|
|
|
//
|
|
|
|
TryAgain = FALSE;
|
|
|
|
if (*Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
|
|
|
|
if (*Buffer != NULL) {
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(*Buffer);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
*Buffer = AllocateZeroPool (BufferSize);
|
|
|
|
|
|
|
|
if (*Buffer != NULL) {
|
|
|
|
TryAgain = TRUE;
|
|
|
|
} else {
|
|
|
|
*Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// If there's an error, free the buffer
|
|
|
|
//
|
2020-04-23 11:08:10 +02:00
|
|
|
if (!TryAgain && EFI_ERROR(*Status) && (*Buffer != NULL)) {
|
|
|
|
FreePool(*Buffer);
|
2019-09-03 11:58:42 +02:00
|
|
|
*Buffer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TryAgain;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Function returns the value of the specified variable.
|
|
|
|
|
|
|
|
|
|
|
|
@param Name A Null-terminated Unicode string that is
|
|
|
|
the name of the vendor's variable.
|
|
|
|
@param VendorGuid A unique identifier for the vendor.
|
|
|
|
|
|
|
|
@return The payload of the variable.
|
|
|
|
@retval NULL If the variable can't be read.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID *
|
|
|
|
EfiLibGetVariable (
|
|
|
|
IN CHAR16 *Name,
|
|
|
|
IN EFI_GUID *VendorGuid
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN VarSize;
|
|
|
|
|
|
|
|
return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Function deletes the variable specified by VarName and VarGuid.
|
|
|
|
|
|
|
|
@param VarName A Null-terminated Unicode string that is
|
|
|
|
the name of the vendor's variable.
|
|
|
|
|
|
|
|
@param VarGuid A unique identifier for the vendor.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS The variable was found and removed
|
|
|
|
@retval EFI_UNSUPPORTED The variable store was inaccessible
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The temporary buffer was not available
|
|
|
|
@retval EFI_NOT_FOUND The variable was not found
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EfiLibDeleteVariable (
|
|
|
|
IN CHAR16 *VarName,
|
|
|
|
IN EFI_GUID *VarGuid
|
|
|
|
)
|
|
|
|
{
|
|
|
|
VOID *VarBuf;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
VarBuf = EfiLibGetVariable (VarName, VarGuid);
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
|
|
|
|
if (VarBuf != NULL) {
|
|
|
|
//
|
|
|
|
// Delete variable from Storage
|
|
|
|
//
|
|
|
|
Status = gRT->SetVariable (
|
|
|
|
VarName,
|
|
|
|
VarGuid,
|
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
);
|
2020-04-23 11:08:10 +02:00
|
|
|
// ASSERT (!EFI_ERROR(Status));
|
|
|
|
FreePool(VarBuf);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
Function gets the file system information from an open file descriptor,
|
|
|
|
and stores it in a buffer allocated from pool.
|
|
|
|
|
|
|
|
|
|
|
|
@param FHand The file handle.
|
|
|
|
|
|
|
|
@return A pointer to a buffer with file information.
|
|
|
|
@retval NULL is returned if failed to get Vaolume Label Info.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_FILE_SYSTEM_VOLUME_LABEL *
|
|
|
|
EfiLibFileSystemVolumeLabelInfo (
|
|
|
|
IN EFI_FILE_HANDLE FHand
|
|
|
|
)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
|
|
EFI_FILE_SYSTEM_VOLUME_LABEL *Buffer;
|
|
|
|
UINTN BufferSize;
|
|
|
|
//
|
|
|
|
// Initialize for GrowBuffer loop
|
|
|
|
//
|
|
|
|
Buffer = NULL;
|
|
|
|
BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Call the real function
|
|
|
|
//
|
|
|
|
while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
|
|
|
|
Status = FHand->GetInfo (
|
|
|
|
FHand,
|
|
|
|
&gEfiFileSystemVolumeLabelInfoIdGuid,
|
|
|
|
&BufferSize,
|
|
|
|
Buffer
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Buffer;
|
|
|
|
#else
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_FILE_SYSTEM_VOLUME_LABEL *VolumeInfo = NULL;
|
|
|
|
UINTN Size = 0;
|
|
|
|
|
|
|
|
Status = FHand->GetInfo (FHand, &gEfiFileSystemVolumeLabelInfoIdGuid, &Size, VolumeInfo);
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
// inc size by 2 because some drivers (HFSPlus.efi) do not count 0 at the end of file name
|
|
|
|
Size += 2;
|
|
|
|
VolumeInfo = AllocateZeroPool (Size);
|
|
|
|
Status = FHand->GetInfo (FHand, &gEfiFileSystemVolumeLabelInfoIdGuid, &Size, VolumeInfo);
|
|
|
|
// Check to make sure this isn't actually EFI_FILE_SYSTEM_INFO
|
|
|
|
if (!EFI_ERROR(Status))
|
|
|
|
{
|
|
|
|
EFI_FILE_SYSTEM_INFO *FSInfo = (EFI_FILE_SYSTEM_INFO *)VolumeInfo;
|
|
|
|
if (FSInfo->Size == (UINT64)Size)
|
|
|
|
{
|
|
|
|
// Allocate a new volume label
|
|
|
|
VolumeInfo = (EFI_FILE_SYSTEM_VOLUME_LABEL *)EfiStrDuplicate(FSInfo->VolumeLabel);
|
|
|
|
FreePool(FSInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!EFI_ERROR(Status))
|
|
|
|
{
|
|
|
|
return VolumeInfo;
|
|
|
|
}
|
|
|
|
FreePool(VolumeInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Duplicate a string.
|
|
|
|
|
|
|
|
@param Src The source.
|
|
|
|
|
|
|
|
@return A new string which is duplicated copy of the source.
|
|
|
|
@retval NULL If there is not enough memory.
|
|
|
|
|
|
|
|
**/
|
|
|
|
CHAR16 *
|
|
|
|
EfiStrDuplicate (
|
|
|
|
IN CHAR16 *Src
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CHAR16 *Dest;
|
|
|
|
UINTN Size;
|
|
|
|
|
|
|
|
Size = StrSize (Src); //at least 2bytes
|
|
|
|
Dest = AllocatePool (Size); //don't need to zero because of CopyMem. SpeedUp
|
|
|
|
// ASSERT (Dest != NULL);
|
|
|
|
if (Dest != NULL) {
|
|
|
|
CopyMem (Dest, Src, Size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
Function gets the file information from an open file descriptor, and stores it
|
|
|
|
in a buffer allocated from pool.
|
|
|
|
|
|
|
|
@param FHand File Handle.
|
|
|
|
|
|
|
|
@return A pointer to a buffer with file information or NULL is returned
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_FILE_INFO *
|
|
|
|
EfiLibFileInfo (
|
|
|
|
IN EFI_FILE_HANDLE FHand
|
|
|
|
)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
|
|
EFI_FILE_INFO *Buffer = NULL;
|
|
|
|
UINTN BufferSize = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize for GrowBuffer loop
|
|
|
|
//
|
|
|
|
Buffer = NULL;
|
|
|
|
BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Call the real function
|
|
|
|
//
|
|
|
|
while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
|
|
|
|
Status = FHand->GetInfo (
|
|
|
|
FHand,
|
|
|
|
&gEfiFileInfoGuid,
|
|
|
|
&BufferSize,
|
|
|
|
Buffer
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return Buffer;
|
|
|
|
#else
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_FILE_INFO *FileInfo = NULL;
|
|
|
|
UINTN Size = 0;
|
|
|
|
|
|
|
|
Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo);
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
// inc size by 2 because some drivers (HFSPlus.efi) do not count 0 at the end of file name
|
|
|
|
Size += 2;
|
|
|
|
FileInfo = AllocateZeroPool (Size);
|
|
|
|
Status = FHand->GetInfo (FHand, &gEfiFileInfoGuid, &Size, FileInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_ERROR(Status)?NULL:FileInfo;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_FILE_SYSTEM_INFO *
|
|
|
|
EfiLibFileSystemInfo (
|
|
|
|
IN EFI_FILE_HANDLE FHand
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_FILE_SYSTEM_INFO *FileSystemInfo = NULL;
|
|
|
|
UINTN Size = 0;
|
|
|
|
|
|
|
|
Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo);
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
// inc size by 2 because some drivers (HFSPlus.efi) do not count 0 at the end of file name
|
|
|
|
Size += 2;
|
|
|
|
FileSystemInfo = AllocateZeroPool (Size);
|
|
|
|
Status = FHand->GetInfo (FHand, &gEfiFileSystemInfoGuid, &Size, FileSystemInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_ERROR(Status)?NULL:FileSystemInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Function is used to determine the number of device path instances
|
|
|
|
that exist in a device path.
|
|
|
|
|
|
|
|
|
|
|
|
@param DevicePath A pointer to a device path data structure.
|
|
|
|
|
|
|
|
@return This function counts and returns the number of device path instances
|
|
|
|
in DevicePath.
|
|
|
|
|
|
|
|
**/
|
|
|
|
UINTN
|
|
|
|
EfiDevicePathInstanceCount (
|
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Count;
|
|
|
|
UINTN Size;
|
|
|
|
|
|
|
|
Count = 0;
|
|
|
|
while (GetNextDevicePathInstance (&DevicePath, &Size) != NULL) {
|
|
|
|
Count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Adjusts the size of a previously allocated buffer.
|
|
|
|
|
|
|
|
|
|
|
|
@param OldPool - A pointer to the buffer whose size is being adjusted.
|
|
|
|
@param OldSize - The size of the current buffer.
|
|
|
|
@param NewSize - The size of the new buffer.
|
|
|
|
|
|
|
|
@return The newly allocated buffer.
|
|
|
|
@retval NULL Allocation failed.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID *
|
|
|
|
EfiReallocatePool (
|
|
|
|
IN VOID *OldPool,
|
|
|
|
IN UINTN OldSize,
|
|
|
|
IN UINTN NewSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
VOID *NewPool;
|
|
|
|
|
|
|
|
NewPool = NULL;
|
|
|
|
if (NewSize != 0) {
|
|
|
|
NewPool = AllocateZeroPool (NewSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OldPool != NULL) {
|
|
|
|
if (NewPool != NULL) {
|
|
|
|
CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
|
|
|
|
}
|
|
|
|
|
2020-04-23 11:08:10 +02:00
|
|
|
FreePool(OldPool);
|
2019-09-03 11:58:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NewPool;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Compare two EFI_TIME data.
|
|
|
|
|
|
|
|
|
|
|
|
@param FirstTime - A pointer to the first EFI_TIME data.
|
|
|
|
@param SecondTime - A pointer to the second EFI_TIME data.
|
|
|
|
|
|
|
|
@retval TRUE The FirstTime is not later than the SecondTime.
|
|
|
|
@retval FALSE The FirstTime is later than the SecondTime.
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
TimeCompare (
|
|
|
|
IN EFI_TIME *FirstTime,
|
|
|
|
IN EFI_TIME *SecondTime
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (FirstTime->Year != SecondTime->Year) {
|
|
|
|
return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
|
|
|
|
} else if (FirstTime->Month != SecondTime->Month) {
|
|
|
|
return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
|
|
|
|
} else if (FirstTime->Day != SecondTime->Day) {
|
|
|
|
return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
|
|
|
|
} else if (FirstTime->Hour != SecondTime->Hour) {
|
|
|
|
return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
|
|
|
|
} else if (FirstTime->Minute != SecondTime->Minute) {
|
|
|
|
return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
|
|
|
|
} else if (FirstTime->Second != SecondTime->Second) {
|
|
|
|
return (BOOLEAN) (FirstTime->Second < SecondTime->Second);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (BOOLEAN) (FirstTime->Nanosecond <= SecondTime->Nanosecond);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Get a string from the Data Hub record based on
|
|
|
|
a device path.
|
|
|
|
|
|
|
|
@param DevPath The device Path.
|
|
|
|
|
|
|
|
@return A string located from the Data Hub records based on
|
|
|
|
the device path.
|
|
|
|
@retval NULL If failed to get the String from Data Hub.
|
|
|
|
|
|
|
|
**/
|
|
|
|
UINT16 *
|
|
|
|
EfiLibStrFromDatahub (
|
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevPath
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|