--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+ BmLib.c\r
+ \r
+AgBStract:\r
+\r
+ Boot Maintainence Helper functions\r
+\r
+--*/\r
+\r
+#include "BootMaint.h"\r
+\r
+EFI_STATUS\r
+EfiLibLocateProtocol (\r
+ IN EFI_GUID *ProtocolGuid,\r
+ OUT VOID **Interface\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Find the first instance of this Protocol \r
+ in the system and return it's interface\r
+\r
+Arguments:\r
+\r
+ ProtocolGuid - Provides the protocol to search for\r
+ Interface - On return, a pointer to the first interface \r
+ that matches ProtocolGuid\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - A protocol instance matching ProtocolGuid was found\r
+\r
+ EFI_NOT_FOUND - No protocol instances were found that match ProtocolGuid\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->LocateProtocol (\r
+ ProtocolGuid,\r
+ NULL,\r
+ Interface\r
+ );\r
+ return Status;\r
+}\r
+\r
+EFI_FILE_HANDLE\r
+EfiLibOpenRoot (\r
+ IN EFI_HANDLE DeviceHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Function opens and returns a file handle to the root directory of a volume.\r
+\r
+Arguments:\r
+\r
+ DeviceHandle - A handle for a device\r
+\r
+Returns:\r
+ \r
+ A valid file handle or NULL is returned\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;\r
+ EFI_FILE_HANDLE File;\r
+\r
+ File = NULL;\r
+\r
+ //\r
+ // File the file system interface to the device\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ (VOID *) &Volume\r
+ );\r
+\r
+ //\r
+ // Open the root directory of the volume\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = Volume->OpenVolume (\r
+ Volume,\r
+ &File\r
+ );\r
+ }\r
+ //\r
+ // Done\r
+ //\r
+ return EFI_ERROR (Status) ? NULL : File;\r
+}\r
+\r
+BOOLEAN\r
+EfiGrowBuffer (\r
+ IN OUT EFI_STATUS *Status,\r
+ IN OUT VOID **Buffer,\r
+ IN UINTN BufferSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Helper function called as part of the code needed\r
+ to allocate the proper sized buffer for various \r
+ EFI interfaces.\r
+\r
+Arguments:\r
+\r
+ Status - Current status\r
+\r
+ Buffer - Current allocated buffer, or NULL\r
+\r
+ BufferSize - Current buffer size needed\r
+ \r
+Returns:\r
+ \r
+ TRUE - if the buffer was reallocated and the caller \r
+ should try the API again.\r
+\r
+--*/\r
+{\r
+ BOOLEAN TryAgain;\r
+\r
+ //\r
+ // If this is an initial request, buffer will be null with a new buffer size\r
+ //\r
+ if (!*Buffer && BufferSize) {\r
+ *Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ //\r
+ // If the status code is "buffer too small", resize the buffer\r
+ //\r
+ TryAgain = FALSE;\r
+ if (*Status == EFI_BUFFER_TOO_SMALL) {\r
+\r
+ SafeFreePool (*Buffer);\r
+\r
+ *Buffer = AllocateZeroPool (BufferSize);\r
+\r
+ if (*Buffer) {\r
+ TryAgain = TRUE;\r
+ } else {\r
+ *Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+ //\r
+ // If there's an error, free the buffer\r
+ //\r
+ if (!TryAgain && EFI_ERROR (*Status) && *Buffer) {\r
+ SafeFreePool (*Buffer);\r
+ *Buffer = NULL;\r
+ }\r
+\r
+ return TryAgain;\r
+}\r
+\r
+VOID *\r
+EfiLibGetVariable (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Function returns the value of the specified variable.\r
+\r
+Arguments:\r
+ Name - A Null-terminated Unicode string that is \r
+ the name of the vendor's variable.\r
+\r
+ VendorGuid - A unique identifier for the vendor.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ UINTN VarSize;\r
+\r
+ return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);\r
+}\r
+\r
+EFI_STATUS\r
+EfiLibDeleteVariable (\r
+ IN CHAR16 *VarName,\r
+ IN EFI_GUID *VarGuid\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Function deletes the variable specified by VarName and VarGuid.\r
+\r
+Arguments:\r
+ VarName - A Null-terminated Unicode string that is \r
+ the name of the vendor's variable.\r
+\r
+ VendorGuid - A unique identifier for the vendor.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The variable was found and removed\r
+\r
+ EFI_UNSUPPORTED - The variable store was inaccessible\r
+\r
+ EFI_OUT_OF_RESOURCES - The temporary buffer was not available\r
+\r
+ EFI_NOT_FOUND - The variable was not found\r
+\r
+--*/\r
+{\r
+ VOID *VarBuf;\r
+ EFI_STATUS Status;\r
+\r
+ VarBuf = EfiLibGetVariable (VarName, VarGuid);\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ if (VarBuf) {\r
+ //\r
+ // Delete variable from Storage\r
+ //\r
+ Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL);\r
+ ASSERT (!EFI_ERROR (Status));\r
+ SafeFreePool (VarBuf);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *\r
+EfiLibFileSystemVolumeLabelInfo (\r
+ IN EFI_FILE_HANDLE FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Function gets the file system information from an open file descriptor, \r
+ and stores it in a buffer allocated from pool.\r
+\r
+Arguments:\r
+\r
+ Fhand - A file handle\r
+\r
+Returns:\r
+ \r
+ A pointer to a buffer with file information or NULL is returned\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Buffer;\r
+ UINTN BufferSize;\r
+ //\r
+ // Initialize for GrowBuffer loop\r
+ //\r
+ Buffer = NULL;\r
+ BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 200;\r
+\r
+ //\r
+ // Call the real function\r
+ //\r
+ while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {\r
+ Status = FHand->GetInfo (\r
+ FHand,\r
+ &gEfiFileSystemVolumeLabelInfoIdGuid,\r
+ &BufferSize,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Buffer;\r
+}\r
+\r
+CHAR16 *\r
+EfiStrDuplicate (\r
+ IN CHAR16 *Src\r
+ )\r
+{\r
+ CHAR16 *Dest;\r
+ UINTN Size;\r
+\r
+ Size = StrSize (Src);\r
+ Dest = AllocateZeroPool (Size);\r
+ ASSERT (Dest != NULL);\r
+ if (Dest) {\r
+ CopyMem (Dest, Src, Size);\r
+ }\r
+\r
+ return Dest;\r
+}\r
+\r
+EFI_FILE_INFO *\r
+EfiLibFileInfo (\r
+ IN EFI_FILE_HANDLE FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Function gets the file information from an open file descriptor, and stores it \r
+ in a buffer allocated from pool.\r
+\r
+Arguments:\r
+\r
+ Fhand - A file handle\r
+\r
+Returns:\r
+ \r
+ A pointer to a buffer with file information or NULL is returned\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_INFO *Buffer;\r
+ UINTN BufferSize;\r
+\r
+ //\r
+ // Initialize for GrowBuffer loop\r
+ //\r
+ Buffer = NULL;\r
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;\r
+\r
+ //\r
+ // Call the real function\r
+ //\r
+ while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {\r
+ Status = FHand->GetInfo (\r
+ FHand,\r
+ &gEfiFileInfoGuid,\r
+ &BufferSize,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Buffer;\r
+}\r
+\r
+UINTN\r
+EfiDevicePathInstanceCount (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Function is used to determine the number of device path instances \r
+ that exist in a device path.\r
+\r
+Arguments:\r
+ DevicePath - A pointer to a device path data structure.\r
+\r
+Returns:\r
+\r
+ This function counts and returns the number of device path instances \r
+ in DevicePath.\r
+\r
+--*/\r
+{\r
+ UINTN Count;\r
+ UINTN Size;\r
+\r
+ Count = 0;\r
+ while (GetNextDevicePathInstance (&DevicePath, &Size)) {\r
+ Count += 1;\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+VOID *\r
+EfiReallocatePool (\r
+ IN VOID *OldPool,\r
+ IN UINTN OldSize,\r
+ IN UINTN NewSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Adjusts the size of a previously allocated buffer.\r
+\r
+Arguments:\r
+ OldPool - A pointer to the buffer whose size is being adjusted.\r
+ OldSize - The size of the current buffer.\r
+ NewSize - The size of the new buffer.\r
+\r
+Returns:\r
+\r
+ EFI_SUCEESS - The requested number of bytes were allocated.\r
+\r
+ EFI_OUT_OF_RESOURCES - The pool requested could not be allocated.\r
+\r
+ EFI_INVALID_PARAMETER - The buffer was invalid.\r
+\r
+--*/\r
+{\r
+ VOID *NewPool;\r
+\r
+ NewPool = NULL;\r
+ if (NewSize) {\r
+ NewPool = AllocateZeroPool (NewSize);\r
+ }\r
+\r
+ if (OldPool) {\r
+ if (NewPool) {\r
+ CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);\r
+ }\r
+\r
+ SafeFreePool (OldPool);\r
+ }\r
+\r
+ return NewPool;\r
+}\r
+\r
+EFI_STATUS\r
+EfiLibGetStringFromToken (\r
+ IN EFI_GUID *ProducerGuid,\r
+ IN STRING_REF Token,\r
+ OUT CHAR16 **String\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Acquire the string associated with the ProducerGuid and return it.\r
+\r
+Arguments:\r
+ \r
+ ProducerGuid - The Guid to search the HII database for\r
+ Token - The token value of the string to extract\r
+ String - The string that is extracted\r
+ \r
+Returns:\r
+\r
+ EFI_SUCCESS - Buffer filled with the requested forms. BufferLength\r
+ was updated.\r
+ EFI_BUFFER_TOO_SMALL - The buffer provided was not large enough to allow the form to be stored.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 HandleBufferLength;\r
+ EFI_HII_HANDLE *HiiHandleBuffer;\r
+ UINTN StringBufferLength;\r
+ UINTN NumberOfHiiHandles;\r
+ UINTN Index;\r
+ UINT16 Length;\r
+ EFI_GUID HiiGuid;\r
+ EFI_HII_PROTOCOL *Hii;\r
+\r
+ //\r
+ // Initialize params.\r
+ //\r
+ HandleBufferLength = 0;\r
+ HiiHandleBuffer = NULL;\r
+ \r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiProtocolGuid,\r
+ NULL,\r
+ (VOID**) &Hii\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ *String = NULL;\r
+ return Status;\r
+ }\r
+ //\r
+ // Get all the Hii handles\r
+ //\r
+ Status = BdsLibGetHiiHandles (Hii, &HandleBufferLength, &HiiHandleBuffer);\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ //\r
+ // Get the Hii Handle that matches the StructureNode->ProducerName\r
+ //\r
+ NumberOfHiiHandles = HandleBufferLength / sizeof (EFI_HII_HANDLE);\r
+ for (Index = 0; Index < NumberOfHiiHandles; Index++) {\r
+ Length = 0;\r
+ Status = ExtractDataFromHiiHandle (\r
+ HiiHandleBuffer[Index],\r
+ &Length,\r
+ NULL,\r
+ &HiiGuid\r
+ );\r
+ if (CompareGuid (ProducerGuid, &HiiGuid)) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Find the string based on the current language\r
+ //\r
+ StringBufferLength = 0x100;\r
+ *String = AllocateZeroPool (0x100);\r
+ ASSERT (*String != NULL);\r
+\r
+ Status = Hii->GetString (\r
+ Hii,\r
+ HiiHandleBuffer[Index],\r
+ Token,\r
+ FALSE,\r
+ NULL,\r
+ &StringBufferLength,\r
+ *String\r
+ );\r
+\r
+ gBS->FreePool (HiiHandleBuffer);\r
+\r
+ return Status;\r
+}\r
+\r
+BOOLEAN\r
+TimeCompare (\r
+ IN EFI_TIME *FirstTime,\r
+ IN EFI_TIME *SecondTime\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Compare two EFI_TIME data.\r
+\r
+Arguments:\r
+\r
+ FirstTime - A pointer to the first EFI_TIME data.\r
+ SecondTime - A pointer to the second EFI_TIME data.\r
+\r
+Returns:\r
+ TRUE The FirstTime is not later than the SecondTime.\r
+ FALSE The FirstTime is later than the SecondTime.\r
+ \r
+--*/\r
+{\r
+ if (FirstTime->Year != SecondTime->Year) {\r
+ return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
+ } else if (FirstTime->Month != SecondTime->Month) {\r
+ return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
+ } else if (FirstTime->Day != SecondTime->Day) {\r
+ return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
+ } else if (FirstTime->Hour != SecondTime->Hour) {\r
+ return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
+ } else if (FirstTime->Minute != SecondTime->Minute) {\r
+ return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
+ } else if (FirstTime->Second != SecondTime->Second) {\r
+ return (BOOLEAN) (FirstTime->Second < SecondTime->Second);\r
+ }\r
+\r
+ return (BOOLEAN) (FirstTime->Nanosecond <= SecondTime->Nanosecond);\r
+}\r
+\r
+UINT16 *\r
+EfiLibStrFromDatahub (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 *Desc;\r
+ EFI_DATA_HUB_PROTOCOL *Datahub;\r
+ UINT64 Count;\r
+ EFI_DATA_RECORD_HEADER *Record;\r
+ EFI_SUBCLASS_TYPE1_HEADER *DataHdr;\r
+ EFI_GUID MiscGuid = EFI_MISC_SUBCLASS_GUID;\r
+ EFI_MISC_ONBOARD_DEVICE_DATA *ob;\r
+ EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *Port;\r
+ EFI_TIME CurTime;\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiDataHubProtocolGuid,\r
+ NULL,\r
+ (VOID**) &Datahub\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Status = gRT->GetTime (&CurTime, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Count = 0;\r
+ do {\r
+ Status = Datahub->GetNextRecord (Datahub, &Count, NULL, &Record);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA && CompareGuid (&Record->DataRecordGuid, &MiscGuid)) {\r
+ //\r
+ // This record is what we need\r
+ //\r
+ DataHdr = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);\r
+ if (EFI_MISC_ONBOARD_DEVICE_RECORD_NUMBER == DataHdr->RecordType) {\r
+ ob = (EFI_MISC_ONBOARD_DEVICE_DATA *) (DataHdr + 1);\r
+ if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &ob->OnBoardDevicePath, DevPath)) {\r
+ EfiLibGetStringFromToken (&Record->ProducerName, ob->OnBoardDeviceDescription, &Desc);\r
+ return Desc;\r
+ }\r
+ }\r
+\r
+ if (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_RECORD_NUMBER == DataHdr->RecordType) {\r
+ Port = (EFI_MISC_PORT_INTERNAL_CONNECTOR_DESIGNATOR_DATA *) (DataHdr + 1);\r
+ if (BdsLibMatchDevicePaths ((EFI_DEVICE_PATH_PROTOCOL *) &Port->PortPath, DevPath)) {\r
+ EfiLibGetStringFromToken (&Record->ProducerName, Port->PortExternalConnectorDesignator, &Desc);\r
+ return Desc;\r
+ }\r
+ }\r
+ }\r
+\r
+ } while (TimeCompare (&Record->LogTime, &CurTime) && Count != 0);\r
+\r
+ return NULL;\r
+}\r