• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
CompareIso639LanguageCode(IN CONST CHAR8 * Language1,IN CONST CHAR8 * Language2)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
EfiGetSystemConfigurationTable(IN EFI_GUID * TableGuid,OUT VOID ** Table)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
EfiCreateProtocolNotifyEvent(IN EFI_GUID * ProtocolGuid,IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,IN VOID * NotifyContext,OPTIONAL OUT VOID ** Registration)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
EfiNamedEventListen(IN CONST EFI_GUID * Name,IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,IN CONST VOID * NotifyContext,OPTIONAL OUT VOID * Registration OPTIONAL)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
EfiNamedEventSignal(IN CONST EFI_GUID * Name)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
EfiGetCurrentTpl(VOID)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
EfiInitializeLock(IN OUT EFI_LOCK * Lock,IN EFI_TPL Priority)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
EfiAcquireLock(IN EFI_LOCK * Lock)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
EfiAcquireLockOrFail(IN EFI_LOCK * Lock)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
EfiReleaseLock(IN EFI_LOCK * Lock)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
EfiTestManagedDevice(IN CONST EFI_HANDLE ControllerHandle,IN CONST EFI_HANDLE DriverBindingHandle,IN CONST EFI_GUID * ProtocolGuid)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
EfiTestChildHandle(IN CONST EFI_HANDLE ControllerHandle,IN CONST EFI_HANDLE ChildHandle,IN CONST EFI_GUID * ProtocolGuid)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
LookupUnicodeString(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN CONST EFI_UNICODE_STRING_TABLE * UnicodeStringTable,OUT CHAR16 ** UnicodeString)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
LookupUnicodeString2(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN CONST EFI_UNICODE_STRING_TABLE * UnicodeStringTable,OUT CHAR16 ** UnicodeString,IN BOOLEAN Iso639Language)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
AddUnicodeString(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN EFI_UNICODE_STRING_TABLE ** UnicodeStringTable,IN CONST CHAR16 * UnicodeString)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
AddUnicodeString2(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN EFI_UNICODE_STRING_TABLE ** UnicodeStringTable,IN CONST CHAR16 * UnicodeString,IN BOOLEAN Iso639Language)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
FreeUnicodeStringTable(IN EFI_UNICODE_STRING_TABLE * UnicodeStringTable)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
GetVariable(IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid)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
GetEfiGlobalVariable(IN CONST CHAR16 * Name)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
GetBestLanguage(IN CONST CHAR8 * SupportedLanguages,IN BOOLEAN Iso639Language,...)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