+ ASSERT(Name != NULL && Guid != NULL && Value != NULL);\r
+\r
+ //\r
+ // Try to get the variable size.\r
+ //\r
+ BufferSize = 0;\r
+ *Value = NULL;\r
+ if (Size != NULL) {\r
+ *Size = 0;\r
+ }\r
+\r
+ if (Attr != NULL) {\r
+ *Attr = 0;\r
+ }\r
+\r
+ Status = gRT->GetVariable((CHAR16 *)Name, (EFI_GUID *)Guid, Attr, &BufferSize, *Value);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Allocate buffer to get the variable.\r
+ //\r
+ *Value = AllocatePool(BufferSize);\r
+ ASSERT(*Value != NULL);\r
+ if (*Value == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Get the variable data.\r
+ //\r
+ Status = gRT->GetVariable((CHAR16 *)Name, (EFI_GUID *)Guid, Attr, &BufferSize, *Value);\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(*Value);\r
+ *Value = NULL;\r
+ }\r
+\r
+ if (Size != NULL) {\r
+ *Size = BufferSize;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Returns a pointer to an allocated buffer that contains the contents of a\r
+ variable retrieved through the UEFI Runtime Service GetVariable(). This\r
+ function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.\r
+ The returned buffer is allocated using AllocatePool(). The caller is\r
+ responsible for freeing this buffer with FreePool().\r
+\r
+ If Name is NULL, then ASSERT().\r
+ If Value is NULL, then ASSERT().\r
+\r
+ @param[in] Name The pointer to a Null-terminated Unicode string.\r
+ @param[out] Value The buffer point saved the variable info.\r
+ @param[out] Size The buffer size of the variable.\r
+\r
+ @return EFI_OUT_OF_RESOURCES Allocate buffer failed.\r
+ @return EFI_SUCCESS Find the specified variable.\r
+ @return Others Errors Return errors from call to gRT->GetVariable.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetEfiGlobalVariable2 (\r
+ IN CONST CHAR16 *Name,\r
+ OUT VOID **Value,\r
+ OUT UINTN *Size OPTIONAL\r
+ )\r
+{\r
+ return GetVariable2 (Name, &gEfiGlobalVariableGuid, Value, Size);\r
+}\r
+\r
+/**\r
+ Returns a pointer to an allocated buffer that contains the best matching language\r
+ from a set of supported languages.\r
+\r
+ This function supports both ISO 639-2 and RFC 4646 language codes, but language\r
+ code types may not be mixed in a single call to this function. The language\r
+ code returned is allocated using AllocatePool(). The caller is responsible for\r
+ freeing the allocated buffer using FreePool(). This function supports a variable\r
+ argument list that allows the caller to pass in a prioritized list of language\r
+ codes to test against all the language codes in SupportedLanguages.\r
+\r
+ If SupportedLanguages is NULL, then ASSERT().\r
+\r
+ @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that\r
+ contains a set of language codes in the format\r
+ specified by Iso639Language.\r
+ @param[in] Iso639Language If not zero, then all language codes are assumed to be\r
+ in ISO 639-2 format. If zero, then all language\r
+ codes are assumed to be in RFC 4646 language format\r
+ @param[in] ... A variable argument list that contains pointers to\r
+ Null-terminated ASCII strings that contain one or more\r
+ language codes in the format specified by Iso639Language.\r
+ The first language code from each of these language\r
+ code lists is used to determine if it is an exact or\r
+ close match to any of the language codes in\r
+ SupportedLanguages. Close matches only apply to RFC 4646\r
+ language codes, and the matching algorithm from RFC 4647\r
+ is used to determine if a close match is present. If\r
+ an exact or close match is found, then the matching\r
+ language code from SupportedLanguages is returned. If\r
+ no matches are found, then the next variable argument\r
+ parameter is evaluated. The variable argument list\r
+ is terminated by a NULL.\r
+\r
+ @retval NULL The best matching language could not be found in SupportedLanguages.\r
+ @retval NULL There are not enough resources available to return the best matching\r
+ language.\r
+ @retval Other A pointer to a Null-terminated ASCII string that is the best matching\r
+ language in SupportedLanguages.\r
+\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+GetBestLanguage (\r
+ IN CONST CHAR8 *SupportedLanguages,\r
+ IN UINTN Iso639Language,\r
+ ...\r
+ )\r
+{\r
+ VA_LIST Args;\r
+ CHAR8 *Language;\r
+ UINTN CompareLength;\r
+ UINTN LanguageLength;\r
+ CONST CHAR8 *Supported;\r
+ CHAR8 *BestLanguage;\r
+\r
+ ASSERT (SupportedLanguages != NULL);\r
+\r
+ VA_START (Args, Iso639Language);\r
+ while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
+ //\r
+ // Default to ISO 639-2 mode\r
+ //\r
+ CompareLength = 3;\r
+ LanguageLength = MIN (3, AsciiStrLen (Language));\r
+\r
+ //\r
+ // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
+ //\r
+ if (Iso639Language == 0) {\r
+ for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
+ }\r
+\r
+ //\r
+ // Trim back the length of Language used until it is empty\r
+ //\r
+ while (LanguageLength > 0) {\r
+ //\r
+ // Loop through all language codes in SupportedLanguages\r
+ //\r
+ for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
+ //\r
+ // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
+ //\r
+ if (Iso639Language == 0) {\r
+ //\r
+ // Skip ';' characters in Supported\r
+ //\r
+ for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
+ //\r
+ // Determine the length of the next language code in Supported\r
+ //\r
+ for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);\r
+ //\r
+ // If Language is longer than the Supported, then skip to the next language\r
+ //\r
+ if (LanguageLength > CompareLength) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // See if the first LanguageLength characters in Supported match Language\r
+ //\r
+ if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
+ VA_END (Args);\r
+ //\r
+ // Allocate, copy, and return the best matching language code from SupportedLanguages\r
+ //\r
+ BestLanguage = AllocateZeroPool (CompareLength + 1);\r
+ if (BestLanguage == NULL) {\r
+ return NULL;\r
+ }\r
+ return CopyMem (BestLanguage, Supported, CompareLength);\r
+ }\r
+ }\r
+\r
+ if (Iso639Language != 0) {\r
+ //\r
+ // If ISO 639 mode, then each language can only be tested once\r
+ //\r
+ LanguageLength = 0;\r
+ } else {\r
+ //\r
+ // If RFC 4646 mode, then trim Language from the right to the next '-' character\r
+ //\r
+ for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);\r
+ }\r
+ }\r
+ }\r
+ VA_END (Args);\r
+\r
+ //\r
+ // No matches were found\r
+ //\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Returns an array of protocol instance that matches the given protocol.\r
+\r
+ @param[in] Protocol Provides the protocol to search for.\r
+ @param[out] NoProtocols The number of protocols returned in Buffer.\r
+ @param[out] Buffer A pointer to the buffer to return the requested\r
+ array of protocol instances that match Protocol.\r
+ The returned buffer is allocated using\r
+ EFI_BOOT_SERVICES.AllocatePool(). The caller is\r
+ responsible for freeing this buffer with\r
+ EFI_BOOT_SERVICES.FreePool().\r
+\r
+ @retval EFI_SUCCESS The array of protocols was returned in Buffer,\r
+ and the number of protocols in Buffer was\r
+ returned in NoProtocols.\r
+ @retval EFI_NOT_FOUND No protocols found.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the\r
+ matching results.\r
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.\r
+ @retval EFI_INVALID_PARAMETER NoProtocols is NULL.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiLocateProtocolBuffer (\r
+ IN EFI_GUID *Protocol,\r
+ OUT UINTN *NoProtocols,\r
+ OUT VOID ***Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN NoHandles;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Check input parameters\r
+ //\r
+ if (Protocol == NULL || NoProtocols == NULL || Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Initialze output parameters\r
+ //\r
+ *NoProtocols = 0;\r
+ *Buffer = NULL;\r
+\r
+ //\r
+ // Retrieve the array of handles that support Protocol\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ Protocol,\r
+ NULL,\r
+ &NoHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Allocate array of protocol instances\r
+ //\r
+ Status = gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ NoHandles * sizeof (VOID *),\r
+ (VOID **)Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Free the handle buffer\r
+ //\r
+ gBS->FreePool (HandleBuffer);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ZeroMem (*Buffer, NoHandles * sizeof (VOID *));\r
+\r
+ //\r
+ // Lookup Protocol on each handle in HandleBuffer to fill in the array of\r
+ // protocol instances. Handle case where protocol instance was present when\r
+ // LocateHandleBuffer() was called, but is not present when HandleProtocol()\r
+ // is called.\r
+ //\r
+ for (Index = 0, *NoProtocols = 0; Index < NoHandles; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ Protocol,\r
+ &((*Buffer)[*NoProtocols])\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ (*NoProtocols)++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Free the handle buffer\r
+ //\r
+ gBS->FreePool (HandleBuffer);\r
+\r
+ //\r
+ // Make sure at least one protocol instance was found\r
+ //\r
+ if (*NoProtocols == 0) {\r
+ gBS->FreePool (*Buffer);\r
+ *Buffer = NULL;\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Open or create a file or directory, possibly creating the chain of\r
+ directories leading up to the directory.\r
+\r
+ EfiOpenFileByDevicePath() first locates EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on\r
+ FilePath, and opens the root directory of that filesystem with\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume().\r
+\r
+ On the remaining device path, the longest initial sequence of\r
+ FILEPATH_DEVICE_PATH nodes is node-wise traversed with\r
+ EFI_FILE_PROTOCOL.Open().\r
+\r
+ (As a consequence, if OpenMode includes EFI_FILE_MODE_CREATE, and Attributes\r
+ includes EFI_FILE_DIRECTORY, and each FILEPATH_DEVICE_PATH specifies a single\r
+ pathname component, then EfiOpenFileByDevicePath() ensures that the specified\r
+ series of subdirectories exist on return.)\r
+\r
+ The EFI_FILE_PROTOCOL identified by the last FILEPATH_DEVICE_PATH node is\r
+ output to the caller; intermediate EFI_FILE_PROTOCOL instances are closed. If\r
+ there are no FILEPATH_DEVICE_PATH nodes past the node that identifies the\r
+ filesystem, then the EFI_FILE_PROTOCOL of the root directory of the\r
+ filesystem is output to the caller. If a device path node that is different\r
+ from FILEPATH_DEVICE_PATH is encountered relative to the filesystem, the\r
+ traversal is stopped with an error, and a NULL EFI_FILE_PROTOCOL is output.\r
+\r
+ @param[in,out] FilePath On input, the device path to the file or directory\r
+ to open or create. The caller is responsible for\r
+ ensuring that the device path pointed-to by FilePath\r
+ is well-formed. On output, FilePath points one past\r
+ the last node in the original device path that has\r
+ been successfully processed. FilePath is set on\r
+ output even if EfiOpenFileByDevicePath() returns an\r
+ error.\r
+\r
+ @param[out] File On error, File is set to NULL. On success, File is\r
+ set to the EFI_FILE_PROTOCOL of the root directory\r
+ of the filesystem, if there are no\r
+ FILEPATH_DEVICE_PATH nodes in FilePath; otherwise,\r
+ File is set to the EFI_FILE_PROTOCOL identified by\r
+ the last node in FilePath.\r
+\r
+ @param[in] OpenMode The OpenMode parameter to pass to\r
+ EFI_FILE_PROTOCOL.Open().\r
+\r
+ @param[in] Attributes The Attributes parameter to pass to\r
+ EFI_FILE_PROTOCOL.Open().\r
+\r
+ @retval EFI_SUCCESS The file or directory has been opened or\r
+ created.\r
+\r
+ @retval EFI_INVALID_PARAMETER FilePath is NULL; or File is NULL; or FilePath\r
+ contains a device path node, past the node\r
+ that identifies\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, that is not a\r
+ FILEPATH_DEVICE_PATH node.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
+\r
+ @return Error codes propagated from the\r
+ LocateDevicePath() and OpenProtocol() boot\r
+ services, and from the\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume()\r
+ and EFI_FILE_PROTOCOL.Open() member functions.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiOpenFileByDevicePath (\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,\r
+ OUT EFI_FILE_PROTOCOL **File,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE FileSystemHandle;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;\r
+ EFI_FILE_PROTOCOL *LastFile;\r
+ FILEPATH_DEVICE_PATH *FilePathNode;\r
+ CHAR16 *AlignedPathName;\r
+ CHAR16 *PathName;\r
+ EFI_FILE_PROTOCOL *NextFile;\r
+\r
+ if (File == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *File = NULL;\r
+\r
+ if (FilePath == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Look up the filesystem.\r
+ //\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ FilePath,\r
+ &FileSystemHandle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Status = gBS->OpenProtocol (\r
+ FileSystemHandle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ (VOID **)&FileSystem,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Open the root directory of the filesystem. After this operation succeeds,\r
+ // we have to release LastFile on error.\r
+ //\r
+ Status = FileSystem->OpenVolume (FileSystem, &LastFile);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Traverse the device path nodes relative to the filesystem.\r
+ //\r
+ while (!IsDevicePathEnd (*FilePath)) {\r
+ if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||\r
+ DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto CloseLastFile;\r
+ }\r
+ FilePathNode = (FILEPATH_DEVICE_PATH *)*FilePath;\r
+\r
+ //\r
+ // FilePathNode->PathName may be unaligned, and the UEFI specification\r
+ // requires pointers that are passed to protocol member functions to be\r
+ // aligned. Create an aligned copy of the pathname if necessary.\r
+ //\r
+ if ((UINTN)FilePathNode->PathName % sizeof *FilePathNode->PathName == 0) {\r
+ AlignedPathName = NULL;\r
+ PathName = FilePathNode->PathName;\r
+ } else {\r
+ AlignedPathName = AllocateCopyPool (\r
+ (DevicePathNodeLength (FilePathNode) -\r
+ SIZE_OF_FILEPATH_DEVICE_PATH),\r
+ FilePathNode->PathName\r
+ );\r
+ if (AlignedPathName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto CloseLastFile;\r
+ }\r
+ PathName = AlignedPathName;\r
+ }\r
+\r
+ //\r
+ // Open or create the file corresponding to the next pathname fragment.\r
+ //\r
+ Status = LastFile->Open (\r
+ LastFile,\r
+ &NextFile,\r
+ PathName,\r
+ OpenMode,\r
+ Attributes\r
+ );\r
+\r
+ //\r
+ // Release any AlignedPathName on both error and success paths; PathName is\r
+ // no longer needed.\r
+ //\r
+ if (AlignedPathName != NULL) {\r
+ FreePool (AlignedPathName);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ goto CloseLastFile;\r
+ }\r
+\r
+ //\r
+ // Advance to the next device path node.\r
+ //\r
+ LastFile->Close (LastFile);\r
+ LastFile = NextFile;\r
+ *FilePath = NextDevicePathNode (FilePathNode);\r
+ }\r
+\r
+ *File = LastFile;\r
+ return EFI_SUCCESS;\r
+\r
+CloseLastFile:\r
+ LastFile->Close (LastFile);\r
+\r
+ //\r
+ // We are on the error path; we must have set an error Status for returning\r
+ // to the caller.\r
+ //\r
+ ASSERT (EFI_ERROR (Status));\r
+ return Status;\r
+}\r