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