Home | History | Annotate | Download | only in FrameworkUefiLib
      1 /** @file
      2   The UEFI Library provides functions and macros that simplify the development of
      3   UEFI Drivers and UEFI Applications.  These functions and macros help manage EFI
      4   events, build simple locks utilizing EFI Task Priority Levels (TPLs), install
      5   EFI Driver Model related protocols, manage Unicode string tables for UEFI Drivers,
      6   and print messages on the console output and standard error devices.
      7 
      8   Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
      9   This program and the accompanying materials
     10   are licensed and made available under the terms and conditions of the BSD License
     11   which accompanies this distribution.  The full text of the license may be found at
     12   http://opensource.org/licenses/bsd-license.php
     13 
     14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 **/
     18 
     19 
     20 #include "UefiLibInternal.h"
     21 
     22 /**
     23   Compare whether two names of languages are identical.
     24 
     25   @param  Language1 Name of language 1.
     26   @param  Language2 Name of language 2.
     27 
     28   @retval TRUE      Language 1 and language 2 are the same.
     29   @retval FALSE     Language 1 and language 2 are not the same.
     30 
     31 **/
     32 BOOLEAN
     33 CompareIso639LanguageCode (
     34   IN CONST CHAR8  *Language1,
     35   IN CONST CHAR8  *Language2
     36   )
     37 {
     38   UINT32  Name1;
     39   UINT32  Name2;
     40 
     41   Name1 = ReadUnaligned24 ((CONST UINT32 *) Language1);
     42   Name2 = ReadUnaligned24 ((CONST UINT32 *) Language2);
     43 
     44   return (BOOLEAN) (Name1 == Name2);
     45 }
     46 
     47 /**
     48   Retrieves a pointer to the system configuration table from the EFI System Table
     49   based on a specified GUID.
     50 
     51   This function searches the list of configuration tables stored in the EFI System Table
     52   for a table with a GUID that matches TableGuid.  If a match is found, then a pointer to
     53   the configuration table is returned in Table., and EFI_SUCCESS is returned. If a matching GUID
     54   is not found, then EFI_NOT_FOUND is returned.
     55   If TableGuid is NULL, then ASSERT().
     56   If Table is NULL, then ASSERT().
     57 
     58   @param  TableGuid       Pointer to table's GUID type..
     59   @param  Table           Pointer to the table associated with TableGuid in the EFI System Table.
     60 
     61   @retval EFI_SUCCESS     A configuration table matching TableGuid was found.
     62   @retval EFI_NOT_FOUND   A configuration table matching TableGuid could not be found.
     63 
     64 **/
     65 EFI_STATUS
     66 EFIAPI
     67 EfiGetSystemConfigurationTable (
     68   IN  EFI_GUID  *TableGuid,
     69   OUT VOID      **Table
     70   )
     71 {
     72   EFI_SYSTEM_TABLE  *SystemTable;
     73   UINTN             Index;
     74 
     75   ASSERT (TableGuid != NULL);
     76   ASSERT (Table != NULL);
     77 
     78   SystemTable = gST;
     79   *Table = NULL;
     80   for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
     81     if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {
     82       *Table = SystemTable->ConfigurationTable[Index].VendorTable;
     83       return EFI_SUCCESS;
     84     }
     85   }
     86 
     87   return EFI_NOT_FOUND;
     88 }
     89 
     90 /**
     91   Creates and returns a notification event and registers that event with all the protocol
     92   instances specified by ProtocolGuid.
     93 
     94   This function causes the notification function to be executed for every protocol of type
     95   ProtocolGuid instance that exists in the system when this function is invoked. If there are
     96   no instances of ProtocolGuid in the handle database at the time this function is invoked,
     97   then the notification function is still executed one time. In addition, every time a protocol
     98   of type ProtocolGuid instance is installed or reinstalled, the notification function is also
     99   executed. This function returns the notification event that was created.
    100   If ProtocolGuid is NULL, then ASSERT().
    101   If NotifyTpl is not a legal TPL value, then ASSERT().
    102   If NotifyFunction is NULL, then ASSERT().
    103   If Registration is NULL, then ASSERT().
    104 
    105 
    106   @param  ProtocolGuid    Supplies GUID of the protocol upon whose installation the event is fired.
    107   @param  NotifyTpl       Supplies the task priority level of the event notifications.
    108   @param  NotifyFunction  Supplies the function to notify when the event is signaled.
    109   @param  NotifyContext   The context parameter to pass to NotifyFunction.
    110   @param  Registration    A pointer to a memory location to receive the registration value.
    111                           This value is passed to LocateHandle() to obtain new handles that
    112                           have been added that support the ProtocolGuid-specified protocol.
    113 
    114   @return The notification event that was created.
    115 
    116 **/
    117 EFI_EVENT
    118 EFIAPI
    119 EfiCreateProtocolNotifyEvent(
    120   IN  EFI_GUID          *ProtocolGuid,
    121   IN  EFI_TPL           NotifyTpl,
    122   IN  EFI_EVENT_NOTIFY  NotifyFunction,
    123   IN  VOID              *NotifyContext,  OPTIONAL
    124   OUT VOID              **Registration
    125   )
    126 {
    127   EFI_STATUS  Status;
    128   EFI_EVENT   Event;
    129 
    130   ASSERT (ProtocolGuid != NULL);
    131   ASSERT (NotifyFunction != NULL);
    132   ASSERT (Registration != NULL);
    133 
    134   //
    135   // Create the event
    136   //
    137 
    138   Status = gBS->CreateEvent (
    139                   EVT_NOTIFY_SIGNAL,
    140                   NotifyTpl,
    141                   NotifyFunction,
    142                   NotifyContext,
    143                   &Event
    144                   );
    145   ASSERT_EFI_ERROR (Status);
    146 
    147   //
    148   // Register for protocol notifications on this event
    149   //
    150 
    151   Status = gBS->RegisterProtocolNotify (
    152                   ProtocolGuid,
    153                   Event,
    154                   Registration
    155                   );
    156 
    157   ASSERT_EFI_ERROR (Status);
    158 
    159   //
    160   // Kick the event so we will perform an initial pass of
    161   // current installed drivers
    162   //
    163 
    164   gBS->SignalEvent (Event);
    165   return Event;
    166 }
    167 
    168 /**
    169   Creates a named event that can be signaled with EfiNamedEventSignal().
    170 
    171   This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.
    172   This event is signaled with EfiNamedEventSignal(). This provides the ability for one or more
    173   listeners on the same event named by the GUID specified by Name.
    174   If Name is NULL, then ASSERT().
    175   If NotifyTpl is not a legal TPL value, then ASSERT().
    176   If NotifyFunction is NULL, then ASSERT().
    177 
    178   @param  Name                  Supplies GUID name of the event.
    179   @param  NotifyTpl             Supplies the task priority level of the event notifications.
    180   @param  NotifyFunction        Supplies the function to notify when the event is signaled.
    181   @param  NotifyContext         The context parameter to pass to NotifyFunction.
    182   @param  Registration          A pointer to a memory location to receive the registration value.
    183 
    184   @retval EFI_SUCCESS           A named event was created.
    185   @retval EFI_OUT_OF_RESOURCES  There are not enough resource to create the named event.
    186 
    187 **/
    188 EFI_STATUS
    189 EFIAPI
    190 EfiNamedEventListen (
    191   IN CONST EFI_GUID    *Name,
    192   IN EFI_TPL           NotifyTpl,
    193   IN EFI_EVENT_NOTIFY  NotifyFunction,
    194   IN CONST VOID        *NotifyContext,  OPTIONAL
    195   OUT VOID             *Registration OPTIONAL
    196   )
    197 {
    198   EFI_STATUS  Status;
    199   EFI_EVENT   Event;
    200   VOID        *RegistrationLocal;
    201 
    202   ASSERT (Name != NULL);
    203   ASSERT (NotifyFunction != NULL);
    204   ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
    205 
    206   //
    207   // Create event
    208   //
    209   Status = gBS->CreateEvent (
    210                   EVT_NOTIFY_SIGNAL,
    211                   NotifyTpl,
    212                   NotifyFunction,
    213                   (VOID *) NotifyContext,
    214                   &Event
    215                   );
    216   ASSERT_EFI_ERROR (Status);
    217 
    218   //
    219   // The Registration is not optional to RegisterProtocolNotify().
    220   // To make it optional to EfiNamedEventListen(), may need to substitute with a local.
    221   //
    222   if (Registration != NULL) {
    223     RegistrationLocal = Registration;
    224   } else {
    225     RegistrationLocal = &RegistrationLocal;
    226   }
    227 
    228   //
    229   // Register for an installation of protocol interface
    230   //
    231 
    232   Status = gBS->RegisterProtocolNotify (
    233                   (EFI_GUID *) Name,
    234                   Event,
    235                   RegistrationLocal
    236                   );
    237   ASSERT_EFI_ERROR (Status);
    238 
    239   return Status;
    240 }
    241 
    242 /**
    243   Signals a named event created with EfiNamedEventListen().
    244 
    245   This function signals the named event specified by Name. The named event must have been
    246   created with EfiNamedEventListen().
    247   If Name is NULL, then ASSERT().
    248 
    249   @param  Name                  Supplies GUID name of the event.
    250 
    251   @retval EFI_SUCCESS           A named event was signaled.
    252   @retval EFI_OUT_OF_RESOURCES  There are not enough resource to signal the named event.
    253 
    254 **/
    255 EFI_STATUS
    256 EFIAPI
    257 EfiNamedEventSignal (
    258   IN CONST EFI_GUID  *Name
    259   )
    260 {
    261   EFI_STATUS  Status;
    262   EFI_HANDLE  Handle;
    263 
    264   ASSERT(Name != NULL);
    265 
    266   Handle = NULL;
    267   Status = gBS->InstallProtocolInterface (
    268                   &Handle,
    269                   (EFI_GUID *) Name,
    270                   EFI_NATIVE_INTERFACE,
    271                   NULL
    272                   );
    273   ASSERT_EFI_ERROR (Status);
    274 
    275   Status = gBS->UninstallProtocolInterface (
    276                   Handle,
    277                   (EFI_GUID *) Name,
    278                   NULL
    279                   );
    280   ASSERT_EFI_ERROR (Status);
    281 
    282   return Status;
    283 }
    284 
    285 /**
    286   Returns the current TPL.
    287 
    288   This function returns the current TPL.  There is no EFI service to directly
    289   retrieve the current TPL. Instead, the RaiseTPL() function is used to raise
    290   the TPL to TPL_HIGH_LEVEL.  This will return the current TPL.  The TPL level
    291   can then immediately be restored back to the current TPL level with a call
    292   to RestoreTPL().
    293 
    294   @return The current TPL.
    295 
    296 **/
    297 EFI_TPL
    298 EFIAPI
    299 EfiGetCurrentTpl (
    300   VOID
    301   )
    302 {
    303   EFI_TPL Tpl;
    304 
    305   Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
    306   gBS->RestoreTPL (Tpl);
    307 
    308   return Tpl;
    309 }
    310 
    311 
    312 /**
    313   Initializes a basic mutual exclusion lock.
    314 
    315   This function initializes a basic mutual exclusion lock to the released state
    316   and returns the lock.  Each lock provides mutual exclusion access at its task
    317   priority level.  Since there is no preemption or multiprocessor support in EFI,
    318   acquiring the lock only consists of raising to the locks TPL.
    319   If Lock is NULL, then ASSERT().
    320   If Priority is not a valid TPL value, then ASSERT().
    321 
    322   @param  Lock       A pointer to the lock data structure to initialize.
    323   @param  Priority   EFI TPL associated with the lock.
    324 
    325   @return The lock.
    326 
    327 **/
    328 EFI_LOCK *
    329 EFIAPI
    330 EfiInitializeLock (
    331   IN OUT EFI_LOCK  *Lock,
    332   IN EFI_TPL        Priority
    333   )
    334 {
    335   ASSERT (Lock != NULL);
    336   ASSERT (Priority <= TPL_HIGH_LEVEL);
    337 
    338   Lock->Tpl       = Priority;
    339   Lock->OwnerTpl  = TPL_APPLICATION;
    340   Lock->Lock      = EfiLockReleased ;
    341   return Lock;
    342 }
    343 
    344 /**
    345   Acquires ownership of a lock.
    346 
    347   This function raises the system's current task priority level to the task
    348   priority level of the mutual exclusion lock.  Then, it places the lock in the
    349   acquired state.
    350   If Lock is NULL, then ASSERT().
    351   If Lock is not initialized, then ASSERT().
    352   If Lock is already in the acquired state, then ASSERT().
    353 
    354   @param  Lock              A pointer to the lock to acquire.
    355 
    356 **/
    357 VOID
    358 EFIAPI
    359 EfiAcquireLock (
    360   IN EFI_LOCK  *Lock
    361   )
    362 {
    363   ASSERT (Lock != NULL);
    364   ASSERT (Lock->Lock == EfiLockReleased);
    365 
    366   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
    367   Lock->Lock     = EfiLockAcquired;
    368 }
    369 
    370 /**
    371   Acquires ownership of a lock.
    372 
    373   This function raises the system's current task priority level to the task priority
    374   level of the mutual exclusion lock.  Then, it attempts to place the lock in the acquired state.
    375   If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
    376   Otherwise, EFI_SUCCESS is returned.
    377   If Lock is NULL, then ASSERT().
    378   If Lock is not initialized, then ASSERT().
    379 
    380   @param  Lock              A pointer to the lock to acquire.
    381 
    382   @retval EFI_SUCCESS       The lock was acquired.
    383   @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
    384 
    385 **/
    386 EFI_STATUS
    387 EFIAPI
    388 EfiAcquireLockOrFail (
    389   IN EFI_LOCK  *Lock
    390   )
    391 {
    392 
    393   ASSERT (Lock != NULL);
    394   ASSERT (Lock->Lock != EfiLockUninitialized);
    395 
    396   if (Lock->Lock == EfiLockAcquired) {
    397     //
    398     // Lock is already owned, so bail out
    399     //
    400     return EFI_ACCESS_DENIED;
    401   }
    402 
    403   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
    404 
    405   Lock->Lock = EfiLockAcquired;
    406 
    407   return EFI_SUCCESS;
    408 }
    409 
    410 /**
    411   Releases ownership of a lock.
    412 
    413   This function transitions a mutual exclusion lock from the acquired state to
    414   the released state, and restores the system's task priority level to its
    415   previous level.
    416   If Lock is NULL, then ASSERT().
    417   If Lock is not initialized, then ASSERT().
    418   If Lock is already in the released state, then ASSERT().
    419 
    420   @param  Lock  A pointer to the lock to release.
    421 
    422 **/
    423 VOID
    424 EFIAPI
    425 EfiReleaseLock (
    426   IN EFI_LOCK  *Lock
    427   )
    428 {
    429   EFI_TPL Tpl;
    430 
    431   ASSERT (Lock != NULL);
    432   ASSERT (Lock->Lock == EfiLockAcquired);
    433 
    434   Tpl = Lock->OwnerTpl;
    435 
    436   Lock->Lock = EfiLockReleased;
    437 
    438   gBS->RestoreTPL (Tpl);
    439 }
    440 
    441 /**
    442   Tests whether a controller handle is being managed by a specific driver.
    443 
    444   This function tests whether the driver specified by DriverBindingHandle is
    445   currently managing the controller specified by ControllerHandle.  This test
    446   is performed by evaluating if the the protocol specified by ProtocolGuid is
    447   present on ControllerHandle and is was opened by DriverBindingHandle with an
    448   attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
    449   If ProtocolGuid is NULL, then ASSERT().
    450 
    451   @param  ControllerHandle     A handle for a controller to test.
    452   @param  DriverBindingHandle  Specifies the driver binding handle for the
    453                                driver.
    454   @param  ProtocolGuid         Specifies the protocol that the driver specified
    455                                by DriverBindingHandle opens in its Start()
    456                                function.
    457 
    458   @retval EFI_SUCCESS          ControllerHandle is managed by the driver
    459                                specified by DriverBindingHandle.
    460   @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
    461                                specified by DriverBindingHandle.
    462 
    463 **/
    464 EFI_STATUS
    465 EFIAPI
    466 EfiTestManagedDevice (
    467   IN CONST EFI_HANDLE       ControllerHandle,
    468   IN CONST EFI_HANDLE       DriverBindingHandle,
    469   IN CONST EFI_GUID         *ProtocolGuid
    470   )
    471 {
    472   EFI_STATUS     Status;
    473   VOID           *ManagedInterface;
    474 
    475   ASSERT (ProtocolGuid != NULL);
    476 
    477   Status = gBS->OpenProtocol (
    478                   ControllerHandle,
    479                   (EFI_GUID *) ProtocolGuid,
    480                   &ManagedInterface,
    481                   DriverBindingHandle,
    482                   ControllerHandle,
    483                   EFI_OPEN_PROTOCOL_BY_DRIVER
    484                   );
    485   if (!EFI_ERROR (Status)) {
    486     gBS->CloseProtocol (
    487            ControllerHandle,
    488            (EFI_GUID *) ProtocolGuid,
    489            DriverBindingHandle,
    490            ControllerHandle
    491            );
    492     return EFI_UNSUPPORTED;
    493   }
    494 
    495   if (Status != EFI_ALREADY_STARTED) {
    496     return EFI_UNSUPPORTED;
    497   }
    498 
    499   return EFI_SUCCESS;
    500 }
    501 
    502 /**
    503   Tests whether a child handle is a child device of the controller.
    504 
    505   This function tests whether ChildHandle is one of the children of
    506   ControllerHandle.  This test is performed by checking to see if the protocol
    507   specified by ProtocolGuid is present on ControllerHandle and opened by
    508   ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
    509   If ProtocolGuid is NULL, then ASSERT().
    510 
    511   @param  ControllerHandle     A handle for a (parent) controller to test.
    512   @param  ChildHandle          A child handle to test.
    513   @param  ProtocolGuid         Supplies the protocol that the child controller
    514                                opens on its parent controller.
    515 
    516   @retval EFI_SUCCESS          ChildHandle is a child of the ControllerHandle.
    517   @retval EFI_UNSUPPORTED      ChildHandle is not a child of the
    518                                ControllerHandle.
    519 
    520 **/
    521 EFI_STATUS
    522 EFIAPI
    523 EfiTestChildHandle (
    524   IN CONST EFI_HANDLE       ControllerHandle,
    525   IN CONST EFI_HANDLE       ChildHandle,
    526   IN CONST EFI_GUID         *ProtocolGuid
    527   )
    528 {
    529   EFI_STATUS                            Status;
    530   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
    531   UINTN                                 EntryCount;
    532   UINTN                                 Index;
    533 
    534   ASSERT (ProtocolGuid != NULL);
    535 
    536   //
    537   // Retrieve the list of agents that are consuming the specific protocol
    538   // on ControllerHandle.
    539   //
    540   Status = gBS->OpenProtocolInformation (
    541                   ControllerHandle,
    542                   (EFI_GUID *) ProtocolGuid,
    543                   &OpenInfoBuffer,
    544                   &EntryCount
    545                   );
    546   if (EFI_ERROR (Status)) {
    547     return EFI_UNSUPPORTED;
    548   }
    549 
    550   //
    551   // Inspect if ChildHandle is one of the agents.
    552   //
    553   Status = EFI_UNSUPPORTED;
    554   for (Index = 0; Index < EntryCount; Index++) {
    555     if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
    556         (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
    557       Status = EFI_SUCCESS;
    558       break;
    559     }
    560   }
    561 
    562   FreePool (OpenInfoBuffer);
    563   return Status;
    564 }
    565 
    566 /**
    567   This function looks up a Unicode string in UnicodeStringTable.
    568 
    569   If Language is a member of SupportedLanguages and a Unicode string is found in
    570   UnicodeStringTable that matches the language code specified by Language, then it
    571   is returned in UnicodeString.
    572 
    573   @param  Language                A pointer to the ISO 639-2 language code for the
    574                                   Unicode string to look up and return.
    575   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
    576                                   that the Unicode string table supports.  Language
    577                                   must be a member of this set.
    578   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
    579   @param  UnicodeString           A pointer to the Unicode string from UnicodeStringTable
    580                                   that matches the language specified by Language.
    581 
    582   @retval EFI_SUCCESS             The Unicode string that matches the language
    583                                   specified by Language was found
    584                                   in the table of Unicode strings UnicodeStringTable,
    585                                   and it was returned in UnicodeString.
    586   @retval EFI_INVALID_PARAMETER   Language is NULL.
    587   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
    588   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
    589   @retval EFI_UNSUPPORTED         UnicodeStringTable is NULL.
    590   @retval EFI_UNSUPPORTED         The language specified by Language is not a
    591                                   member of SupportedLanguages.
    592   @retval EFI_UNSUPPORTED         The language specified by Language is not
    593                                   supported by UnicodeStringTable.
    594 
    595 **/
    596 EFI_STATUS
    597 EFIAPI
    598 LookupUnicodeString (
    599   IN CONST CHAR8                     *Language,
    600   IN CONST CHAR8                     *SupportedLanguages,
    601   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
    602   OUT CHAR16                         **UnicodeString
    603   )
    604 {
    605   //
    606   // Make sure the parameters are valid
    607   //
    608   if (Language == NULL || UnicodeString == NULL) {
    609     return EFI_INVALID_PARAMETER;
    610   }
    611 
    612   //
    613   // If there are no supported languages, or the Unicode String Table is empty, then the
    614   // Unicode String specified by Language is not supported by this Unicode String Table
    615   //
    616   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
    617     return EFI_UNSUPPORTED;
    618   }
    619 
    620   //
    621   // Make sure Language is in the set of Supported Languages
    622   //
    623   while (*SupportedLanguages != 0) {
    624     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
    625 
    626       //
    627       // Search the Unicode String Table for the matching Language specifier
    628       //
    629       while (UnicodeStringTable->Language != NULL) {
    630         if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
    631 
    632           //
    633           // A matching string was found, so return it
    634           //
    635           *UnicodeString = UnicodeStringTable->UnicodeString;
    636           return EFI_SUCCESS;
    637         }
    638 
    639         UnicodeStringTable++;
    640       }
    641 
    642       return EFI_UNSUPPORTED;
    643     }
    644 
    645     SupportedLanguages += 3;
    646   }
    647 
    648   return EFI_UNSUPPORTED;
    649 }
    650 
    651 
    652 
    653 /**
    654   This function looks up a Unicode string in UnicodeStringTable.
    655 
    656   If Language is a member of SupportedLanguages and a Unicode string is found in
    657   UnicodeStringTable that matches the language code specified by Language, then
    658   it is returned in UnicodeString.
    659 
    660   @param  Language             A pointer to an ASCII string containing the ISO 639-2 or the
    661                                RFC 4646 language code for the Unicode string to look up and
    662                                return. If Iso639Language is TRUE, then this ASCII string is
    663                                not assumed to be Null-terminated, and only the first three
    664                                characters are used. If Iso639Language is FALSE, then this ASCII
    665                                string must be Null-terminated.
    666   @param  SupportedLanguages   A pointer to a Null-terminated ASCII string that contains a
    667                                set of ISO 639-2 or RFC 4646 language codes that the Unicode
    668                                string table supports.  Language must be a member of this set.
    669                                If Iso639Language is TRUE, then this string contains one or more
    670                                ISO 639-2 language codes with no separator characters. If Iso639Language
    671                                is FALSE, then is string contains one or more RFC 4646 language
    672                                codes separated by ';'.
    673   @param  UnicodeStringTable   A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
    674                                is defined in "Related Definitions".
    675   @param  UnicodeString        A pointer to the Null-terminated Unicode string from UnicodeStringTable
    676                                that matches the language specified by Language.
    677   @param  Iso639Language       Specifies the supported language code format. If it is TRUE, then
    678                                Language and SupportedLanguages follow ISO 639-2 language code format.
    679                                Otherwise, they follow RFC 4646 language code format.
    680 
    681 
    682   @retval  EFI_SUCCESS            The Unicode string that matches the language specified by Language
    683                                   was found in the table of Unicode strings UnicodeStringTable, and
    684                                   it was returned in UnicodeString.
    685   @retval  EFI_INVALID_PARAMETER  Language is NULL.
    686   @retval  EFI_INVALID_PARAMETER  UnicodeString is NULL.
    687   @retval  EFI_UNSUPPORTED        SupportedLanguages is NULL.
    688   @retval  EFI_UNSUPPORTED        UnicodeStringTable is NULL.
    689   @retval  EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
    690   @retval  EFI_UNSUPPORTED        The language specified by Language is not supported by UnicodeStringTable.
    691 
    692 **/
    693 EFI_STATUS
    694 EFIAPI
    695 LookupUnicodeString2 (
    696   IN CONST CHAR8                     *Language,
    697   IN CONST CHAR8                     *SupportedLanguages,
    698   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
    699   OUT CHAR16                         **UnicodeString,
    700   IN BOOLEAN                         Iso639Language
    701   )
    702 {
    703   BOOLEAN   Found;
    704   UINTN     Index;
    705   CHAR8     *LanguageString;
    706 
    707   //
    708   // Make sure the parameters are valid
    709   //
    710   if (Language == NULL || UnicodeString == NULL) {
    711     return EFI_INVALID_PARAMETER;
    712   }
    713 
    714   //
    715   // If there are no supported languages, or the Unicode String Table is empty, then the
    716   // Unicode String specified by Language is not supported by this Unicode String Table
    717   //
    718   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
    719     return EFI_UNSUPPORTED;
    720   }
    721 
    722   //
    723   // Make sure Language is in the set of Supported Languages
    724   //
    725   Found = FALSE;
    726   while (*SupportedLanguages != 0) {
    727     if (Iso639Language) {
    728       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
    729         Found = TRUE;
    730         break;
    731       }
    732       SupportedLanguages += 3;
    733     } else {
    734       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
    735       if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
    736         Found = TRUE;
    737         break;
    738       }
    739       SupportedLanguages += Index;
    740       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
    741     }
    742   }
    743 
    744   //
    745   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
    746   //
    747   if (!Found) {
    748     return EFI_UNSUPPORTED;
    749   }
    750 
    751   //
    752   // Search the Unicode String Table for the matching Language specifier
    753   //
    754   while (UnicodeStringTable->Language != NULL) {
    755     LanguageString = UnicodeStringTable->Language;
    756     while (0 != *LanguageString) {
    757       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
    758       if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {
    759         *UnicodeString = UnicodeStringTable->UnicodeString;
    760         return EFI_SUCCESS;
    761       }
    762       LanguageString += Index;
    763       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);
    764     }
    765     UnicodeStringTable++;
    766   }
    767 
    768   return EFI_UNSUPPORTED;
    769 }
    770 
    771 
    772 /**
    773   This function adds a Unicode string to UnicodeStringTable.
    774 
    775   If Language is a member of SupportedLanguages then UnicodeString is added to
    776   UnicodeStringTable.  New buffers are allocated for both Language and
    777   UnicodeString.  The contents of Language and UnicodeString are copied into
    778   these new buffers.  These buffers are automatically freed when
    779   FreeUnicodeStringTable() is called.
    780 
    781   @param  Language                A pointer to the ISO 639-2 language code for the Unicode
    782                                   string to add.
    783   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
    784                                   that the Unicode string table supports.
    785                                   Language must be a member of this set.
    786   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
    787   @param  UnicodeString           A pointer to the Unicode string to add.
    788 
    789   @retval EFI_SUCCESS             The Unicode string that matches the language
    790                                   specified by Language was found in the table of
    791                                   Unicode strings UnicodeStringTable, and it was
    792                                   returned in UnicodeString.
    793   @retval EFI_INVALID_PARAMETER   Language is NULL.
    794   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
    795   @retval EFI_INVALID_PARAMETER   UnicodeString is an empty string.
    796   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
    797   @retval EFI_ALREADY_STARTED     A Unicode string with language Language is
    798                                   already present in UnicodeStringTable.
    799   @retval EFI_OUT_OF_RESOURCES    There is not enough memory to add another
    800                                   Unicode string to UnicodeStringTable.
    801   @retval EFI_UNSUPPORTED         The language specified by Language is not a
    802                                   member of SupportedLanguages.
    803 
    804 **/
    805 EFI_STATUS
    806 EFIAPI
    807 AddUnicodeString (
    808   IN CONST CHAR8               *Language,
    809   IN CONST CHAR8               *SupportedLanguages,
    810   IN EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
    811   IN CONST CHAR16              *UnicodeString
    812   )
    813 {
    814   UINTN                     NumberOfEntries;
    815   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
    816   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
    817   UINTN                     UnicodeStringLength;
    818 
    819   //
    820   // Make sure the parameter are valid
    821   //
    822   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
    823     return EFI_INVALID_PARAMETER;
    824   }
    825 
    826   //
    827   // If there are no supported languages, then a Unicode String can not be added
    828   //
    829   if (SupportedLanguages == NULL) {
    830     return EFI_UNSUPPORTED;
    831   }
    832 
    833   //
    834   // If the Unicode String is empty, then a Unicode String can not be added
    835   //
    836   if (UnicodeString[0] == 0) {
    837     return EFI_INVALID_PARAMETER;
    838   }
    839 
    840   //
    841   // Make sure Language is a member of SupportedLanguages
    842   //
    843   while (*SupportedLanguages != 0) {
    844     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
    845 
    846       //
    847       // Determine the size of the Unicode String Table by looking for a NULL Language entry
    848       //
    849       NumberOfEntries = 0;
    850       if (*UnicodeStringTable != NULL) {
    851         OldUnicodeStringTable = *UnicodeStringTable;
    852         while (OldUnicodeStringTable->Language != NULL) {
    853           if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
    854             return EFI_ALREADY_STARTED;
    855           }
    856 
    857           OldUnicodeStringTable++;
    858           NumberOfEntries++;
    859         }
    860       }
    861 
    862       //
    863       // Allocate space for a new Unicode String Table.  It must hold the current number of
    864       // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
    865       // marker
    866       //
    867       NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
    868       if (NewUnicodeStringTable == NULL) {
    869         return EFI_OUT_OF_RESOURCES;
    870       }
    871 
    872       //
    873       // If the current Unicode String Table contains any entries, then copy them to the
    874       // newly allocated Unicode String Table.
    875       //
    876       if (*UnicodeStringTable != NULL) {
    877         CopyMem (
    878            NewUnicodeStringTable,
    879            *UnicodeStringTable,
    880            NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
    881            );
    882       }
    883 
    884       //
    885       // Allocate space for a copy of the Language specifier
    886       //
    887       NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
    888       if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
    889         gBS->FreePool (NewUnicodeStringTable);
    890         return EFI_OUT_OF_RESOURCES;
    891       }
    892 
    893       //
    894       // Compute the length of the Unicode String
    895       //
    896       for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
    897         ;
    898 
    899       //
    900       // Allocate space for a copy of the Unicode String
    901       //
    902       NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
    903                                                               (UnicodeStringLength + 1) * sizeof (CHAR16),
    904                                                               UnicodeString
    905                                                               );
    906       if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
    907         gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
    908         gBS->FreePool (NewUnicodeStringTable);
    909         return EFI_OUT_OF_RESOURCES;
    910       }
    911 
    912       //
    913       // Mark the end of the Unicode String Table
    914       //
    915       NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
    916       NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
    917 
    918       //
    919       // Free the old Unicode String Table
    920       //
    921       if (*UnicodeStringTable != NULL) {
    922         gBS->FreePool (*UnicodeStringTable);
    923       }
    924 
    925       //
    926       // Point UnicodeStringTable at the newly allocated Unicode String Table
    927       //
    928       *UnicodeStringTable = NewUnicodeStringTable;
    929 
    930       return EFI_SUCCESS;
    931     }
    932 
    933     SupportedLanguages += 3;
    934   }
    935 
    936   return EFI_UNSUPPORTED;
    937 }
    938 
    939 
    940 /**
    941   This function adds the Null-terminated Unicode string specified by UnicodeString
    942   to UnicodeStringTable.
    943 
    944   If Language is a member of SupportedLanguages then UnicodeString is added to
    945   UnicodeStringTable.  New buffers are allocated for both Language and UnicodeString.
    946   The contents of Language and UnicodeString are copied into these new buffers.
    947   These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called.
    948 
    949   @param  Language            A pointer to an ASCII string containing the ISO 639-2 or
    950                               the RFC 4646 language code for the Unicode string to add.
    951                               If Iso639Language is TRUE, then this ASCII string is not
    952                               assumed to be Null-terminated, and only the first three
    953                               chacters are used. If Iso639Language is FALSE, then this
    954                               ASCII string must be Null-terminated.
    955   @param  SupportedLanguages  A pointer to a Null-terminated ASCII string that contains
    956                               a set of ISO 639-2 or RFC 4646 language codes that the Unicode
    957                               string table supports.  Language must be a member of this set.
    958                               If Iso639Language is TRUE, then this string contains one or more
    959                               ISO 639-2 language codes with no separator characters.
    960                               If Iso639Language is FALSE, then is string contains one or more
    961                               RFC 4646 language codes separated by ';'.
    962   @param  UnicodeStringTable  A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
    963                               is defined in "Related Definitions".
    964   @param  UnicodeString       A pointer to the Unicode string to add.
    965   @param  Iso639Language      Specifies the supported language code format. If it is TRUE,
    966                               then Language and SupportedLanguages follow ISO 639-2 language code format.
    967                               Otherwise, they follow RFC 4646 language code format.
    968 
    969   @retval EFI_SUCCESS            The Unicode string that matches the language specified by
    970                                  Language was found in the table of Unicode strings UnicodeStringTable,
    971                                  and it was returned in UnicodeString.
    972   @retval EFI_INVALID_PARAMETER  Language is NULL.
    973   @retval EFI_INVALID_PARAMETER  UnicodeString is NULL.
    974   @retval EFI_INVALID_PARAMETER  UnicodeString is an empty string.
    975   @retval EFI_UNSUPPORTED        SupportedLanguages is NULL.
    976   @retval EFI_ALREADY_STARTED    A Unicode string with language Language is already present in
    977                                  UnicodeStringTable.
    978   @retval EFI_OUT_OF_RESOURCES   There is not enough memory to add another Unicode string UnicodeStringTable.
    979   @retval EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
    980 
    981 **/
    982 EFI_STATUS
    983 EFIAPI
    984 AddUnicodeString2 (
    985   IN CONST CHAR8               *Language,
    986   IN CONST CHAR8               *SupportedLanguages,
    987   IN EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
    988   IN CONST CHAR16              *UnicodeString,
    989   IN BOOLEAN                   Iso639Language
    990   )
    991 {
    992   UINTN                     NumberOfEntries;
    993   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
    994   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
    995   UINTN                     UnicodeStringLength;
    996   BOOLEAN                   Found;
    997   UINTN                     Index;
    998   CHAR8                     *LanguageString;
    999 
   1000   //
   1001   // Make sure the parameter are valid
   1002   //
   1003   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
   1004     return EFI_INVALID_PARAMETER;
   1005   }
   1006 
   1007   //
   1008   // If there are no supported languages, then a Unicode String can not be added
   1009   //
   1010   if (SupportedLanguages == NULL) {
   1011     return EFI_UNSUPPORTED;
   1012   }
   1013 
   1014   //
   1015   // If the Unicode String is empty, then a Unicode String can not be added
   1016   //
   1017   if (UnicodeString[0] == 0) {
   1018     return EFI_INVALID_PARAMETER;
   1019   }
   1020 
   1021   //
   1022   // Make sure Language is a member of SupportedLanguages
   1023   //
   1024   Found = FALSE;
   1025   while (*SupportedLanguages != 0) {
   1026     if (Iso639Language) {
   1027       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
   1028         Found = TRUE;
   1029         break;
   1030       }
   1031       SupportedLanguages += 3;
   1032     } else {
   1033       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
   1034       if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {
   1035         Found = TRUE;
   1036         break;
   1037       }
   1038       SupportedLanguages += Index;
   1039       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
   1040     }
   1041   }
   1042 
   1043   //
   1044   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
   1045   //
   1046   if (!Found) {
   1047     return EFI_UNSUPPORTED;
   1048   }
   1049 
   1050   //
   1051   // Determine the size of the Unicode String Table by looking for a NULL Language entry
   1052   //
   1053   NumberOfEntries = 0;
   1054   if (*UnicodeStringTable != NULL) {
   1055     OldUnicodeStringTable = *UnicodeStringTable;
   1056     while (OldUnicodeStringTable->Language != NULL) {
   1057       LanguageString = OldUnicodeStringTable->Language;
   1058 
   1059       while (*LanguageString != 0) {
   1060         for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
   1061 
   1062         if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
   1063           return EFI_ALREADY_STARTED;
   1064         }
   1065         LanguageString += Index;
   1066         for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);
   1067       }
   1068       OldUnicodeStringTable++;
   1069       NumberOfEntries++;
   1070     }
   1071   }
   1072 
   1073   //
   1074   // Allocate space for a new Unicode String Table.  It must hold the current number of
   1075   // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
   1076   // marker
   1077   //
   1078   NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
   1079   if (NewUnicodeStringTable == NULL) {
   1080     return EFI_OUT_OF_RESOURCES;
   1081   }
   1082 
   1083   //
   1084   // If the current Unicode String Table contains any entries, then copy them to the
   1085   // newly allocated Unicode String Table.
   1086   //
   1087   if (*UnicodeStringTable != NULL) {
   1088     CopyMem (
   1089       NewUnicodeStringTable,
   1090       *UnicodeStringTable,
   1091       NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
   1092       );
   1093   }
   1094 
   1095   //
   1096   // Allocate space for a copy of the Language specifier
   1097   //
   1098   NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);
   1099   if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
   1100     gBS->FreePool (NewUnicodeStringTable);
   1101     return EFI_OUT_OF_RESOURCES;
   1102   }
   1103 
   1104   //
   1105   // Compute the length of the Unicode String
   1106   //
   1107   for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);
   1108 
   1109   //
   1110   // Allocate space for a copy of the Unicode String
   1111   //
   1112   NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
   1113   if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
   1114     gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
   1115     gBS->FreePool (NewUnicodeStringTable);
   1116     return EFI_OUT_OF_RESOURCES;
   1117   }
   1118 
   1119   //
   1120   // Mark the end of the Unicode String Table
   1121   //
   1122   NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
   1123   NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
   1124 
   1125   //
   1126   // Free the old Unicode String Table
   1127   //
   1128   if (*UnicodeStringTable != NULL) {
   1129     gBS->FreePool (*UnicodeStringTable);
   1130   }
   1131 
   1132   //
   1133   // Point UnicodeStringTable at the newly allocated Unicode String Table
   1134   //
   1135   *UnicodeStringTable = NewUnicodeStringTable;
   1136 
   1137   return EFI_SUCCESS;
   1138 }
   1139 
   1140 /**
   1141   This function frees the table of Unicode strings in UnicodeStringTable.
   1142 
   1143   If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
   1144   Otherwise, each language code, and each Unicode string in the Unicode string
   1145   table are freed, and EFI_SUCCESS is returned.
   1146 
   1147   @param  UnicodeStringTable  A pointer to the table of Unicode strings.
   1148 
   1149   @retval EFI_SUCCESS         The Unicode string table was freed.
   1150 
   1151 **/
   1152 EFI_STATUS
   1153 EFIAPI
   1154 FreeUnicodeStringTable (
   1155   IN EFI_UNICODE_STRING_TABLE  *UnicodeStringTable
   1156   )
   1157 {
   1158   UINTN Index;
   1159 
   1160   //
   1161   // If the Unicode String Table is NULL, then it is already freed
   1162   //
   1163   if (UnicodeStringTable == NULL) {
   1164     return EFI_SUCCESS;
   1165   }
   1166 
   1167   //
   1168   // Loop through the Unicode String Table until we reach the end of table marker
   1169   //
   1170   for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
   1171 
   1172     //
   1173     // Free the Language string from the Unicode String Table
   1174     //
   1175     gBS->FreePool (UnicodeStringTable[Index].Language);
   1176 
   1177     //
   1178     // Free the Unicode String from the Unicode String Table
   1179     //
   1180     if (UnicodeStringTable[Index].UnicodeString != NULL) {
   1181       gBS->FreePool (UnicodeStringTable[Index].UnicodeString);
   1182     }
   1183   }
   1184 
   1185   //
   1186   // Free the Unicode String Table itself
   1187   //
   1188   gBS->FreePool (UnicodeStringTable);
   1189 
   1190   return EFI_SUCCESS;
   1191 }
   1192 
   1193 /**
   1194   Returns a pointer to an allocated buffer that contains the contents of a
   1195   variable retrieved through the UEFI Runtime Service GetVariable().  The
   1196   returned buffer is allocated using AllocatePool().  The caller is responsible
   1197   for freeing this buffer with FreePool().
   1198 
   1199   If Name is NULL, then ASSERT().
   1200   If Guid is NULL, then ASSERT().
   1201 
   1202   @param[in]  Name  Pointer to a Null-terminated Unicode string.
   1203   @param[in]  Guid  Pointer to an EFI_GUID structure
   1204 
   1205   @retval NULL   The variable could not be retrieved.
   1206   @retval NULL   There are not enough resources available for the variable contents.
   1207   @retval Other  A pointer to allocated buffer containing the variable contents.
   1208 
   1209 **/
   1210 VOID *
   1211 EFIAPI
   1212 GetVariable (
   1213   IN CONST CHAR16    *Name,
   1214   IN CONST EFI_GUID  *Guid
   1215   )
   1216 {
   1217   EFI_STATUS  Status;
   1218   UINTN       Size;
   1219   VOID        *Value;
   1220 
   1221   ASSERT (Name != NULL);
   1222   ASSERT (Guid != NULL);
   1223 
   1224   //
   1225   // Try to get the variable size.
   1226   //
   1227   Value = NULL;
   1228   Size = 0;
   1229   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
   1230   if (Status != EFI_BUFFER_TOO_SMALL) {
   1231     return NULL;
   1232   }
   1233 
   1234   //
   1235   // Allocate buffer to get the variable.
   1236   //
   1237   Value = AllocatePool (Size);
   1238   if (Value == NULL) {
   1239     return NULL;
   1240   }
   1241 
   1242   //
   1243   // Get the variable data.
   1244   //
   1245   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
   1246   if (EFI_ERROR (Status)) {
   1247     FreePool(Value);
   1248     return NULL;
   1249   }
   1250 
   1251   return Value;
   1252 }
   1253 
   1254 
   1255 /**
   1256   Returns a pointer to an allocated buffer that contains the contents of a
   1257   variable retrieved through the UEFI Runtime Service GetVariable().  This
   1258   function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
   1259   The returned buffer is allocated using AllocatePool().  The caller is
   1260   responsible for freeing this buffer with FreePool().
   1261 
   1262   If Name is NULL, then ASSERT().
   1263 
   1264   @param[in]  Name  Pointer to a Null-terminated Unicode string.
   1265 
   1266   @retval NULL   The variable could not be retrieved.
   1267   @retval NULL   There are not enough resources available for the variable contents.
   1268   @retval Other  A pointer to allocated buffer containing the variable contents.
   1269 
   1270 **/
   1271 VOID *
   1272 EFIAPI
   1273 GetEfiGlobalVariable (
   1274   IN CONST CHAR16  *Name
   1275   )
   1276 {
   1277   return GetVariable (Name, &gEfiGlobalVariableGuid);
   1278 }
   1279 
   1280 
   1281 /**
   1282   Returns a pointer to an allocated buffer that contains the best matching language
   1283   from a set of supported languages.
   1284 
   1285   This function supports both ISO 639-2 and RFC 4646 language codes, but language
   1286   code types may not be mixed in a single call to this function.  The language
   1287   code returned is allocated using AllocatePool().  The caller is responsible for
   1288   freeing the allocated buffer using FreePool().  This function supports a variable
   1289   argument list that allows the caller to pass in a prioritized list of language
   1290   codes to test against all the language codes in SupportedLanguages.
   1291 
   1292   If SupportedLanguages is NULL, then ASSERT().
   1293 
   1294   @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
   1295                                   contains a set of language codes in the format
   1296                                   specified by Iso639Language.
   1297   @param[in]  Iso639Language      If TRUE, then all language codes are assumed to be
   1298                                   in ISO 639-2 format.  If FALSE, then all language
   1299                                   codes are assumed to be in RFC 4646 language format
   1300   @param[in]  ...                 A variable argument list that contains pointers to
   1301                                   Null-terminated ASCII strings that contain one or more
   1302                                   language codes in the format specified by Iso639Language.
   1303                                   The first language code from each of these language
   1304                                   code lists is used to determine if it is an exact or
   1305                                   close match to any of the language codes in
   1306                                   SupportedLanguages.  Close matches only apply to RFC 4646
   1307                                   language codes, and the matching algorithm from RFC 4647
   1308                                   is used to determine if a close match is present.  If
   1309                                   an exact or close match is found, then the matching
   1310                                   language code from SupportedLanguages is returned.  If
   1311                                   no matches are found, then the next variable argument
   1312                                   parameter is evaluated.  The variable argument list
   1313                                   is terminated by a NULL.
   1314 
   1315   @retval NULL   The best matching language could not be found in SupportedLanguages.
   1316   @retval NULL   There are not enough resources available to return the best matching
   1317                  language.
   1318   @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
   1319                  language in SupportedLanguages.
   1320 
   1321 **/
   1322 CHAR8 *
   1323 EFIAPI
   1324 GetBestLanguage (
   1325   IN CONST CHAR8  *SupportedLanguages,
   1326   IN BOOLEAN      Iso639Language,
   1327   ...
   1328   )
   1329 {
   1330   VA_LIST      Args;
   1331   CHAR8        *Language;
   1332   UINTN        CompareLength;
   1333   UINTN        LanguageLength;
   1334   CONST CHAR8  *Supported;
   1335   CHAR8        *BestLanguage;
   1336 
   1337   ASSERT (SupportedLanguages != NULL);
   1338 
   1339   VA_START (Args, Iso639Language);
   1340   while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
   1341     //
   1342     // Default to ISO 639-2 mode
   1343     //
   1344     CompareLength  = 3;
   1345     LanguageLength = MIN (3, AsciiStrLen (Language));
   1346 
   1347     //
   1348     // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
   1349     //
   1350     if (!Iso639Language) {
   1351       for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
   1352     }
   1353 
   1354     //
   1355     // Trim back the length of Language used until it is empty
   1356     //
   1357     while (LanguageLength > 0) {
   1358       //
   1359       // Loop through all language codes in SupportedLanguages
   1360       //
   1361       for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
   1362         //
   1363         // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
   1364         //
   1365         if (!Iso639Language) {
   1366           //
   1367           // Skip ';' characters in Supported
   1368           //
   1369           for (; *Supported != '\0' && *Supported == ';'; Supported++);
   1370           //
   1371           // Determine the length of the next language code in Supported
   1372           //
   1373           for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
   1374           //
   1375           // If Language is longer than the Supported, then skip to the next language
   1376           //
   1377           if (LanguageLength > CompareLength) {
   1378             continue;
   1379           }
   1380         }
   1381         //
   1382         // See if the first LanguageLength characters in Supported match Language
   1383         //
   1384         if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
   1385           VA_END (Args);
   1386           //
   1387           // Allocate, copy, and return the best matching language code from SupportedLanguages
   1388           //
   1389           BestLanguage = AllocateZeroPool (CompareLength + 1);
   1390           if (BestLanguage == NULL) {
   1391             return NULL;
   1392           }
   1393           return CopyMem (BestLanguage, Supported, CompareLength);
   1394         }
   1395       }
   1396 
   1397       if (Iso639Language) {
   1398         //
   1399         // If ISO 639 mode, then each language can only be tested once
   1400         //
   1401         LanguageLength = 0;
   1402       } else {
   1403         //
   1404         // If RFC 4646 mode, then trim Language from the right to the next '-' character
   1405         //
   1406         for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
   1407       }
   1408     }
   1409   }
   1410   VA_END (Args);
   1411 
   1412   //
   1413   // No matches were found
   1414   //
   1415   return NULL;
   1416 }
   1417 
   1418