--- /dev/null
+/** @file\r
+ Mde UEFI library functions.\r
+\r
+ Copyright (c) 2006 - 2007, Intel Corporation<BR>\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: UefiLib.c\r
+\r
+**/\r
+\r
+/**\r
+ Compare whether two names of languages are identical.\r
+\r
+ @param Language1 Name of language 1.\r
+ @param Language2 Name of language 2.\r
+\r
+ @retval TRUE Language 1 and language 2 are the same.\r
+ @retval FALSE Language 1 and language 2 are not the same.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+CompareIso639LanguageCode (\r
+ IN CONST CHAR8 *Language1,\r
+ IN CONST CHAR8 *Language2\r
+ )\r
+{\r
+ UINT32 Name1;\r
+ UINT32 Name2;\r
+\r
+ Name1 = ReadUnaligned24 ((CONST UINT32 *) Language1);\r
+ Name2 = ReadUnaligned24 ((CONST UINT32 *) Language2);\r
+\r
+ return (BOOLEAN) (Name1 == Name2);\r
+}\r
+\r
+/**\r
+ This function searches the list of configuration tables stored in the EFI System \r
+ Table for a table with a GUID that matches TableGuid. If a match is found, \r
+ then a pointer to the configuration table is returned in Table, and EFI_SUCCESS \r
+ is returned. If a matching GUID is not found, then EFI_NOT_FOUND is returned.\r
+\r
+ @param TableGuid Pointer to table's GUID type..\r
+ @param Table Pointer to the table associated with TableGuid in the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS A configuration table matching TableGuid was found.\r
+ @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiGetSystemConfigurationTable ( \r
+ IN EFI_GUID *TableGuid,\r
+ OUT VOID **Table\r
+ )\r
+{\r
+ EFI_SYSTEM_TABLE *SystemTable;\r
+ UINTN Index;\r
+\r
+ ASSERT (TableGuid != NULL);\r
+ ASSERT (Table != NULL);\r
+\r
+ SystemTable = gST;\r
+ *Table = NULL;\r
+ for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {\r
+ if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {\r
+ *Table = SystemTable->ConfigurationTable[Index].VendorTable;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ This function causes the notification function to be executed for every protocol \r
+ of type ProtocolGuid instance that exists in the system when this function is \r
+ invoked. In addition, every time a protocol of type ProtocolGuid instance is \r
+ installed or reinstalled, the notification function is also executed.\r
+\r
+ @param ProtocolGuid Supplies GUID of the protocol upon whose installation the event is fired.\r
+ @param NotifyTpl Supplies the task priority level of the event notifications.\r
+ @param NotifyFunction Supplies the function to notify when the event is signaled.\r
+ @param NotifyContext The context parameter to pass to NotifyFunction.\r
+ @param Registration A pointer to a memory location to receive the registration value.\r
+\r
+ @return The notification event that was created. \r
+\r
+**/\r
+EFI_EVENT\r
+EFIAPI\r
+EfiCreateProtocolNotifyEvent(\r
+ IN EFI_GUID *ProtocolGuid,\r
+ IN EFI_TPL NotifyTpl,\r
+ IN EFI_EVENT_NOTIFY NotifyFunction,\r
+ IN VOID *NotifyContext, OPTIONAL\r
+ OUT VOID **Registration\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ //\r
+ // Create the event\r
+ //\r
+\r
+ Status = gBS->CreateEvent (\r
+ EFI_EVENT_NOTIFY_SIGNAL,\r
+ NotifyTpl,\r
+ NotifyFunction,\r
+ NotifyContext,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Register for protocol notifactions on this event\r
+ //\r
+\r
+ Status = gBS->RegisterProtocolNotify (\r
+ ProtocolGuid,\r
+ Event,\r
+ Registration\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Kick the event so we will perform an initial pass of\r
+ // current installed drivers\r
+ //\r
+\r
+ gBS->SignalEvent (Event);\r
+ return Event;\r
+}\r
+\r
+/**\r
+ This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.\r
+ This event is signaled with EfiNamedEventSignal(). This provide the ability for \r
+ one or more listeners on the same event named by the GUID specified by Name.\r
+\r
+ @param Name Supplies GUID name of the event.\r
+ @param NotifyTpl Supplies the task priority level of the event notifications.\r
+ @param NotifyFunction Supplies the function to notify when the event is signaled.\r
+ @param NotifyContext The context parameter to pass to NotifyFunction. \r
+ @param Registration A pointer to a memory location to receive the registration value.\r
+\r
+ @retval EFI_SUCCESS A named event was created.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiNamedEventListen (\r
+ IN CONST EFI_GUID *Name,\r
+ IN EFI_TPL NotifyTpl,\r
+ IN EFI_EVENT_NOTIFY NotifyFunction,\r
+ IN CONST VOID *NotifyContext, OPTIONAL\r
+ OUT VOID *Registration OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+ VOID *RegistrationLocal;\r
+\r
+ //\r
+ // Create event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EFI_EVENT_NOTIFY_SIGNAL,\r
+ NotifyTpl,\r
+ NotifyFunction,\r
+ (VOID *) NotifyContext,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // The Registration is not optional to RegisterProtocolNotify().\r
+ // To make it optional to EfiNamedEventListen(), may need to substitute with a local.\r
+ //\r
+ if (Registration != NULL) {\r
+ RegistrationLocal = Registration;\r
+ } else {\r
+ RegistrationLocal = &RegistrationLocal;\r
+ }\r
+\r
+ //\r
+ // Register for an installation of protocol interface\r
+ //\r
+\r
+ Status = gBS->RegisterProtocolNotify (\r
+ (EFI_GUID *) Name,\r
+ Event,\r
+ RegistrationLocal\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function signals the named event specified by Name. The named event must \r
+ have been created with EfiNamedEventListen().\r
+\r
+ @param Name Supplies GUID name of the event.\r
+\r
+ @retval EFI_SUCCESS A named event was signaled.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resource to signal the named event.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiNamedEventSignal (\r
+ IN CONST EFI_GUID *Name\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+\r
+ Handle = NULL;\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Handle,\r
+ (EFI_GUID *) Name,\r
+ EFI_NATIVE_INTERFACE,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Handle,\r
+ (EFI_GUID *) Name,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** \r
+ Returns the current TPL.\r
+\r
+ This function returns the current TPL. There is no EFI service to directly \r
+ retrieve the current TPL. Instead, the RaiseTPL() function is used to raise \r
+ the TPL to TPL_HIGH_LEVEL. This will return the current TPL. The TPL level \r
+ can then immediately be restored back to the current TPL level with a call \r
+ to RestoreTPL().\r
+\r
+ @param VOID\r
+\r
+ @retvale EFI_TPL The current TPL.\r
+\r
+**/\r
+EFI_TPL\r
+EFIAPI\r
+EfiGetCurrentTpl (\r
+ VOID\r
+ )\r
+{\r
+ EFI_TPL Tpl;\r
+\r
+ Tpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); \r
+ gBS->RestoreTPL (Tpl);\r
+\r
+ return Tpl;\r
+}\r
+\r
+\r
+/**\r
+ This function initializes a basic mutual exclusion lock to the released state \r
+ and returns the lock. Each lock provides mutual exclusion access at its task \r
+ priority level. Since there is no preemption or multiprocessor support in EFI,\r
+ acquiring the lock only consists of raising to the locks TPL.\r
+\r
+ @param Lock A pointer to the lock data structure to initialize.\r
+ @param Priority EFI TPL associated with the lock.\r
+\r
+ @return The lock.\r
+\r
+**/\r
+EFI_LOCK *\r
+EFIAPI\r
+EfiInitializeLock (\r
+ IN OUT EFI_LOCK *Lock,\r
+ IN EFI_TPL Priority\r
+ )\r
+{\r
+ ASSERT (Lock != NULL);\r
+ ASSERT (Priority <= EFI_TPL_HIGH_LEVEL);\r
+\r
+ Lock->Tpl = Priority;\r
+ Lock->OwnerTpl = EFI_TPL_APPLICATION;\r
+ Lock->Lock = EfiLockReleased ;\r
+ return Lock;\r
+}\r
+\r
+/**\r
+ This function raises the system's current task priority level to the task \r
+ priority level of the mutual exclusion lock. Then, it places the lock in the \r
+ acquired state.\r
+\r
+ @param Priority The task priority level of the lock.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiAcquireLock (\r
+ IN EFI_LOCK *Lock\r
+ )\r
+{\r
+ ASSERT (Lock != NULL);\r
+ ASSERT (Lock->Lock == EfiLockReleased);\r
+\r
+ Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);\r
+ Lock->Lock = EfiLockAcquired;\r
+}\r
+\r
+/**\r
+ This function raises the system's current task priority level to the task \r
+ priority level of the mutual exclusion lock. Then, it attempts to place the \r
+ lock in the acquired state.\r
+\r
+ @param Lock A pointer to the lock to acquire.\r
+\r
+ @retval EFI_SUCCESS The lock was acquired.\r
+ @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiAcquireLockOrFail (\r
+ IN EFI_LOCK *Lock\r
+ )\r
+{\r
+\r
+ ASSERT (Lock != NULL);\r
+ ASSERT (Lock->Lock != EfiLockUninitialized);\r
+\r
+ if (Lock->Lock == EfiLockAcquired) {\r
+ //\r
+ // Lock is already owned, so bail out\r
+ //\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);\r
+\r
+ Lock->Lock = EfiLockAcquired;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function transitions a mutual exclusion lock from the acquired state to \r
+ the released state, and restores the system's task priority level to its \r
+ previous level.\r
+\r
+ @param Lock A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiReleaseLock (\r
+ IN EFI_LOCK *Lock\r
+ )\r
+{\r
+ EFI_TPL Tpl;\r
+\r
+ ASSERT (Lock != NULL);\r
+ ASSERT (Lock->Lock == EfiLockAcquired);\r
+\r
+ Tpl = Lock->OwnerTpl;\r
+ \r
+ Lock->Lock = EfiLockReleased;\r
+\r
+ gBS->RestoreTPL (Tpl);\r
+}\r
+\r
+/**
+ Tests whether a controller handle is being managed by a specific driver.
+
+ This function tests whether the driver specified by DriverBindingHandle is\r
+ currently managing the controller specified by ControllerHandle. This test\r
+ is performed by evaluating if the the protocol specified by ProtocolGuid is\r
+ present on ControllerHandle and is was opened by DriverBindingHandle with an\r
+ attribute of EFI_OPEN_PROTOCOL_BY_DRIVER. \r
+ If ProtocolGuid is NULL, then ASSERT().\r
+
+ @param ControllerHandle A handle for a controller to test.
+ @param DriverBindingHandle Specifies the driver binding handle for the
+ driver.
+ @param ProtocolGuid Specifies the protocol that the driver specified
+ by DriverBindingHandle opens in its Start()
+ function.
+
+ @retval EFI_SUCCESS ControllerHandle is managed by the driver
+ specifed by DriverBindingHandle.
+ @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
+ specifed by DriverBindingHandle.
+
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiTestManagedDevice (\r
+ IN CONST EFI_HANDLE ControllerHandle,\r
+ IN CONST EFI_HANDLE DriverBindingHandle,\r
+ IN CONST EFI_GUID *ProtocolGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *ManagedInterface;\r
+\r
+ ASSERT (ProtocolGuid != NULL);\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ (EFI_GUID *) ProtocolGuid,\r
+ &ManagedInterface,\r
+ DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ (EFI_GUID *) ProtocolGuid,\r
+ DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (Status != EFI_ALREADY_STARTED) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**
+ Tests whether a child handle is a child device of the controller.
+
+ This function tests whether ChildHandle is one of the children of\r
+ ControllerHandle. This test is performed by checking to see if the protocol\r
+ specified by ProtocolGuid is present on ControllerHandle and opened by\r
+ ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+ If ProtocolGuid is NULL, then ASSERT().\r
+
+ @param ControllerHandle A handle for a (parent) controller to test.
+ @param ChildHandle A child handle to test.
+ @param ConsumsedGuid Supplies the protocol that the child controller
+ opens on its parent controller.
+
+ @retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle.
+ @retval EFI_UNSUPPORTED ChildHandle is not a child of the
+ ControllerHandle.
+
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiTestChildHandle (\r
+ IN CONST EFI_HANDLE ControllerHandle,\r
+ IN CONST EFI_HANDLE ChildHandle,\r
+ IN CONST EFI_GUID *ProtocolGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
+ UINTN EntryCount;\r
+ UINTN Index;\r
+\r
+ ASSERT (ProtocolGuid != NULL);\r
+\r
+ //\r
+ // Retrieve the list of agents that are consuming the specific protocol\r
+ // on ControllerHandle.\r
+ //\r
+ Status = gBS->OpenProtocolInformation (\r
+ ControllerHandle,\r
+ (EFI_GUID *) ProtocolGuid,\r
+ &OpenInfoBuffer,\r
+ &EntryCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Inspect if ChildHandle is one of the agents.\r
+ //\r
+ Status = EFI_UNSUPPORTED;\r
+ for (Index = 0; Index < EntryCount; Index++) {\r
+ if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&\r
+ (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ FreePool (OpenInfoBuffer);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function looks up a Unicode string in UnicodeStringTable. If Language is \r
+ a member of SupportedLanguages and a Unicode string is found in UnicodeStringTable\r
+ that matches the language code specified by Language, then it is returned in \r
+ UnicodeString.\r
+\r
+ @param Language A pointer to the ISO 639-2 language code for the \r
+ Unicode string to look up and return.\r
+ @param SupportedLanguages A pointer to the set of ISO 639-2 language codes \r
+ that the Unicode string table supports. Language \r
+ must be a member of this set.\r
+ @param UnicodeStringTable A pointer to the table of Unicode strings.\r
+ @param UnicodeString A pointer to the Unicode string from UnicodeStringTable\r
+ that matches the language specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string that matches the language \r
+ specified by Language was found\r
+ in the table of Unicoide strings UnicodeStringTable, \r
+ and it was returned in UnicodeString.\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+ @retval EFI_INVALID_PARAMETER UnicodeString is NULL.\r
+ @retval EFI_UNSUPPORTED SupportedLanguages is NULL.\r
+ @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.\r
+ @retval EFI_UNSUPPORTED The language specified by Language is not a \r
+ member of SupportedLanguages.\r
+ @retval EFI_UNSUPPORTED The language specified by Language is not \r
+ supported by UnicodeStringTable.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LookupUnicodeString (\r
+ IN CONST CHAR8 *Language,\r
+ IN CONST CHAR8 *SupportedLanguages,\r
+ IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,\r
+ OUT CHAR16 **UnicodeString\r
+ )\r
+{\r
+ //\r
+ // Make sure the parameters are valid\r
+ //\r
+ if (Language == NULL || UnicodeString == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If there are no supported languages, or the Unicode String Table is empty, then the\r
+ // Unicode String specified by Language is not supported by this Unicode String Table\r
+ //\r
+ if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Make sure Language is in the set of Supported Languages\r
+ //\r
+ while (*SupportedLanguages != 0) {\r
+ if (CompareIso639LanguageCode (Language, SupportedLanguages)) {\r
+\r
+ //\r
+ // Search the Unicode String Table for the matching Language specifier\r
+ //\r
+ while (UnicodeStringTable->Language != NULL) {\r
+ if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {\r
+\r
+ //\r
+ // A matching string was found, so return it\r
+ //\r
+ *UnicodeString = UnicodeStringTable->UnicodeString;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ UnicodeStringTable++;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ SupportedLanguages += 3;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ This function adds a Unicode string to UnicodeStringTable.\r
+ If Language is a member of SupportedLanguages then UnicodeString is added to \r
+ UnicodeStringTable. New buffers are allocated for both Language and \r
+ UnicodeString. The contents of Language and UnicodeString are copied into \r
+ these new buffers. These buffers are automatically freed when \r
+ FreeUnicodeStringTable() is called.\r
+\r
+ @param Language A pointer to the ISO 639-2 language code for the Unicode \r
+ string to add.\r
+ @param SupportedLanguages A pointer to the set of ISO 639-2 language codes\r
+ that the Unicode string table supports.\r
+ Language must be a member of this set.\r
+ @param UnicodeStringTable A pointer to the table of Unicode strings.\r
+ @param UnicodeString A pointer to the Unicode string to add.\r
+\r
+ @retval EFI_SUCCESS The Unicode string that matches the language \r
+ specified by Language was found in the table of \r
+ Unicode strings UnicodeStringTable, and it was \r
+ returned in UnicodeString.\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+ @retval EFI_INVALID_PARAMETER UnicodeString is NULL.\r
+ @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.\r
+ @retval EFI_UNSUPPORTED SupportedLanguages is NULL.\r
+ @retval EFI_ALREADY_STARTED A Unicode string with language Language is \r
+ already present in UnicodeStringTable.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to add another \r
+ Unicode string to UnicodeStringTable.\r
+ @retval EFI_UNSUPPORTED The language specified by Language is not a \r
+ member of SupportedLanguages.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AddUnicodeString (\r
+ IN CONST CHAR8 *Language,\r
+ IN CONST CHAR8 *SupportedLanguages,\r
+ IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,\r
+ IN CONST CHAR16 *UnicodeString\r
+ )\r
+{\r
+ UINTN NumberOfEntries;\r
+ EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;\r
+ EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;\r
+ UINTN UnicodeStringLength;\r
+\r
+ //\r
+ // Make sure the parameter are valid\r
+ //\r
+ if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If there are no supported languages, then a Unicode String can not be added\r
+ //\r
+ if (SupportedLanguages == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // If the Unicode String is empty, then a Unicode String can not be added\r
+ //\r
+ if (UnicodeString[0] == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Make sure Language is a member of SupportedLanguages\r
+ //\r
+ while (*SupportedLanguages != 0) {\r
+ if (CompareIso639LanguageCode (Language, SupportedLanguages)) {\r
+\r
+ //\r
+ // Determine the size of the Unicode String Table by looking for a NULL Language entry\r
+ //\r
+ NumberOfEntries = 0;\r
+ if (*UnicodeStringTable != NULL) {\r
+ OldUnicodeStringTable = *UnicodeStringTable;\r
+ while (OldUnicodeStringTable->Language != NULL) {\r
+ if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ OldUnicodeStringTable++;\r
+ NumberOfEntries++;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Allocate space for a new Unicode String Table. It must hold the current number of\r
+ // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table\r
+ // marker\r
+ //\r
+ NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));\r
+ if (NewUnicodeStringTable == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // If the current Unicode String Table contains any entries, then copy them to the\r
+ // newly allocated Unicode String Table.\r
+ //\r
+ if (*UnicodeStringTable != NULL) {\r
+ CopyMem (\r
+ NewUnicodeStringTable,\r
+ *UnicodeStringTable,\r
+ NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)\r
+ );\r
+ }\r
+\r
+ //\r
+ // Allocate space for a copy of the Language specifier\r
+ //\r
+ NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);\r
+ if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {\r
+ gBS->FreePool (NewUnicodeStringTable);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Compute the length of the Unicode String\r
+ //\r
+ for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)\r
+ ;\r
+\r
+ //\r
+ // Allocate space for a copy of the Unicode String\r
+ //\r
+ NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (\r
+ (UnicodeStringLength + 1) * sizeof (CHAR16),\r
+ UnicodeString\r
+ );\r
+ if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {\r
+ gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);\r
+ gBS->FreePool (NewUnicodeStringTable);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Mark the end of the Unicode String Table\r
+ //\r
+ NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;\r
+ NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;\r
+\r
+ //\r
+ // Free the old Unicode String Table\r
+ //\r
+ if (*UnicodeStringTable != NULL) {\r
+ gBS->FreePool (*UnicodeStringTable);\r
+ }\r
+\r
+ //\r
+ // Point UnicodeStringTable at the newly allocated Unicode String Table\r
+ //\r
+ *UnicodeStringTable = NewUnicodeStringTable;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ SupportedLanguages += 3;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ This function frees the table of Unicode strings in UnicodeStringTable.\r
+ If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.\r
+ Otherwise, each language code, and each Unicode string in the Unicode string \r
+ table are freed, and EFI_SUCCESS is returned.\r
+\r
+ @param UnicodeStringTable A pointer to the table of Unicode strings.\r
+\r
+ @retval EFI_SUCCESS The Unicode string table was freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FreeUnicodeStringTable (\r
+ IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // If the Unicode String Table is NULL, then it is already freed\r
+ //\r
+ if (UnicodeStringTable == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Loop through the Unicode String Table until we reach the end of table marker\r
+ //\r
+ for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {\r
+\r
+ //\r
+ // Free the Language string from the Unicode String Table\r
+ //\r
+ gBS->FreePool (UnicodeStringTable[Index].Language);\r
+\r
+ //\r
+ // Free the Unicode String from the Unicode String Table\r
+ //\r
+ if (UnicodeStringTable[Index].UnicodeString != NULL) {\r
+ gBS->FreePool (UnicodeStringTable[Index].UnicodeString);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Free the Unicode String Table itself\r
+ //\r
+ gBS->FreePool (UnicodeStringTable);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r