]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OldMdePkg/Library/UefiLib/UefiLib.c
Moved the MdePkg to OldMdePkg so that new code in MdePkg does not break existing...
[mirror_edk2.git] / OldMdePkg / Library / UefiLib / UefiLib.c
diff --git a/OldMdePkg/Library/UefiLib/UefiLib.c b/OldMdePkg/Library/UefiLib/UefiLib.c
new file mode 100644 (file)
index 0000000..f03b881
--- /dev/null
@@ -0,0 +1,811 @@
+/** @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