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   Signals an event group by placing a new event in the group temporarily and
309   signaling it.
310 
311   @param[in] EventGroup          Supplies the unique identifier of the event
312                                  group to signal.
313 
314   @retval EFI_SUCCESS            The event group was signaled successfully.
315   @retval EFI_INVALID_PARAMETER  EventGroup is NULL.
316   @return                        Error codes that report problems about event
317                                  creation or signaling.
318 **/
319 EFI_STATUS
320 EFIAPI
EfiEventGroupSignal(IN CONST EFI_GUID * EventGroup)321 EfiEventGroupSignal (
322   IN CONST EFI_GUID *EventGroup
323   )
324 {
325   EFI_STATUS Status;
326   EFI_EVENT  Event;
327 
328   if (EventGroup == NULL) {
329     return EFI_INVALID_PARAMETER;
330   }
331 
332   Status = gBS->CreateEventEx (
333                   EVT_NOTIFY_SIGNAL,
334                   TPL_CALLBACK,
335                   InternalEmptyFunction,
336                   NULL,
337                   EventGroup,
338                   &Event
339                   );
340   if (EFI_ERROR (Status)) {
341     return Status;
342   }
343 
344   Status = gBS->SignalEvent (Event);
345   gBS->CloseEvent (Event);
346 
347   return Status;
348 }
349 
350 /**
351   Returns the current TPL.
352 
353   This function returns the current TPL.  There is no EFI service to directly
354   retrieve the current TPL. Instead, the RaiseTPL() function is used to raise
355   the TPL to TPL_HIGH_LEVEL.  This will return the current TPL.  The TPL level
356   can then immediately be restored back to the current TPL level with a call
357   to RestoreTPL().
358 
359   @return The current TPL.
360 
361 **/
362 EFI_TPL
363 EFIAPI
EfiGetCurrentTpl(VOID)364 EfiGetCurrentTpl (
365   VOID
366   )
367 {
368   EFI_TPL Tpl;
369 
370   Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
371   gBS->RestoreTPL (Tpl);
372 
373   return Tpl;
374 }
375 
376 
377 /**
378   Initializes a basic mutual exclusion lock.
379 
380   This function initializes a basic mutual exclusion lock to the released state
381   and returns the lock.  Each lock provides mutual exclusion access at its task
382   priority level.  Since there is no preemption or multiprocessor support in EFI,
383   acquiring the lock only consists of raising to the locks TPL.
384   If Lock is NULL, then ASSERT().
385   If Priority is not a valid TPL value, then ASSERT().
386 
387   @param  Lock       A pointer to the lock data structure to initialize.
388   @param  Priority   EFI TPL is associated with the lock.
389 
390   @return The lock.
391 
392 **/
393 EFI_LOCK *
394 EFIAPI
EfiInitializeLock(IN OUT EFI_LOCK * Lock,IN EFI_TPL Priority)395 EfiInitializeLock (
396   IN OUT EFI_LOCK  *Lock,
397   IN EFI_TPL        Priority
398   )
399 {
400   ASSERT (Lock != NULL);
401   ASSERT (Priority <= TPL_HIGH_LEVEL);
402 
403   Lock->Tpl       = Priority;
404   Lock->OwnerTpl  = TPL_APPLICATION;
405   Lock->Lock      = EfiLockReleased ;
406   return Lock;
407 }
408 
409 /**
410   Acquires ownership of a lock.
411 
412   This function raises the system's current task priority level to the task
413   priority level of the mutual exclusion lock.  Then, it places the lock in the
414   acquired state.
415   If Lock is NULL, then ASSERT().
416   If Lock is not initialized, then ASSERT().
417   If Lock is already in the acquired state, then ASSERT().
418 
419   @param  Lock              A pointer to the lock to acquire.
420 
421 **/
422 VOID
423 EFIAPI
EfiAcquireLock(IN EFI_LOCK * Lock)424 EfiAcquireLock (
425   IN EFI_LOCK  *Lock
426   )
427 {
428   ASSERT (Lock != NULL);
429   ASSERT (Lock->Lock == EfiLockReleased);
430 
431   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
432   Lock->Lock     = EfiLockAcquired;
433 }
434 
435 /**
436   Acquires ownership of a lock.
437 
438   This function raises the system's current task priority level to the task priority
439   level of the mutual exclusion lock.  Then, it attempts to place the lock in the acquired state.
440   If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
441   Otherwise, EFI_SUCCESS is returned.
442   If Lock is NULL, then ASSERT().
443   If Lock is not initialized, then ASSERT().
444 
445   @param  Lock              A pointer to the lock to acquire.
446 
447   @retval EFI_SUCCESS       The lock was acquired.
448   @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
449 
450 **/
451 EFI_STATUS
452 EFIAPI
EfiAcquireLockOrFail(IN EFI_LOCK * Lock)453 EfiAcquireLockOrFail (
454   IN EFI_LOCK  *Lock
455   )
456 {
457 
458   ASSERT (Lock != NULL);
459   ASSERT (Lock->Lock != EfiLockUninitialized);
460 
461   if (Lock->Lock == EfiLockAcquired) {
462     //
463     // Lock is already owned, so bail out
464     //
465     return EFI_ACCESS_DENIED;
466   }
467 
468   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
469 
470   Lock->Lock = EfiLockAcquired;
471 
472   return EFI_SUCCESS;
473 }
474 
475 /**
476   Releases ownership of a lock.
477 
478   This function transitions a mutual exclusion lock from the acquired state to
479   the released state, and restores the system's task priority level to its
480   previous level.
481   If Lock is NULL, then ASSERT().
482   If Lock is not initialized, then ASSERT().
483   If Lock is already in the released state, then ASSERT().
484 
485   @param  Lock  A pointer to the lock to release.
486 
487 **/
488 VOID
489 EFIAPI
EfiReleaseLock(IN EFI_LOCK * Lock)490 EfiReleaseLock (
491   IN EFI_LOCK  *Lock
492   )
493 {
494   EFI_TPL Tpl;
495 
496   ASSERT (Lock != NULL);
497   ASSERT (Lock->Lock == EfiLockAcquired);
498 
499   Tpl = Lock->OwnerTpl;
500 
501   Lock->Lock = EfiLockReleased;
502 
503   gBS->RestoreTPL (Tpl);
504 }
505 
506 /**
507   Tests whether a controller handle is being managed by a specific driver.
508 
509   This function tests whether the driver specified by DriverBindingHandle is
510   currently managing the controller specified by ControllerHandle.  This test
511   is performed by evaluating if the the protocol specified by ProtocolGuid is
512   present on ControllerHandle and is was opened by DriverBindingHandle with an
513   attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
514   If ProtocolGuid is NULL, then ASSERT().
515 
516   @param  ControllerHandle     A handle for a controller to test.
517   @param  DriverBindingHandle  Specifies the driver binding handle for the
518                                driver.
519   @param  ProtocolGuid         Specifies the protocol that the driver specified
520                                by DriverBindingHandle opens in its Start()
521                                function.
522 
523   @retval EFI_SUCCESS          ControllerHandle is managed by the driver
524                                specified by DriverBindingHandle.
525   @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
526                                specified by DriverBindingHandle.
527 
528 **/
529 EFI_STATUS
530 EFIAPI
EfiTestManagedDevice(IN CONST EFI_HANDLE ControllerHandle,IN CONST EFI_HANDLE DriverBindingHandle,IN CONST EFI_GUID * ProtocolGuid)531 EfiTestManagedDevice (
532   IN CONST EFI_HANDLE       ControllerHandle,
533   IN CONST EFI_HANDLE       DriverBindingHandle,
534   IN CONST EFI_GUID         *ProtocolGuid
535   )
536 {
537   EFI_STATUS     Status;
538   VOID           *ManagedInterface;
539 
540   ASSERT (ProtocolGuid != NULL);
541 
542   Status = gBS->OpenProtocol (
543                   ControllerHandle,
544                   (EFI_GUID *) ProtocolGuid,
545                   &ManagedInterface,
546                   DriverBindingHandle,
547                   ControllerHandle,
548                   EFI_OPEN_PROTOCOL_BY_DRIVER
549                   );
550   if (!EFI_ERROR (Status)) {
551     gBS->CloseProtocol (
552            ControllerHandle,
553            (EFI_GUID *) ProtocolGuid,
554            DriverBindingHandle,
555            ControllerHandle
556            );
557     return EFI_UNSUPPORTED;
558   }
559 
560   if (Status != EFI_ALREADY_STARTED) {
561     return EFI_UNSUPPORTED;
562   }
563 
564   return EFI_SUCCESS;
565 }
566 
567 /**
568   Tests whether a child handle is a child device of the controller.
569 
570   This function tests whether ChildHandle is one of the children of
571   ControllerHandle.  This test is performed by checking to see if the protocol
572   specified by ProtocolGuid is present on ControllerHandle and opened by
573   ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
574   If ProtocolGuid is NULL, then ASSERT().
575 
576   @param  ControllerHandle     A handle for a (parent) controller to test.
577   @param  ChildHandle          A child handle to test.
578   @param  ProtocolGuid         Supplies the protocol that the child controller
579                                opens on its parent controller.
580 
581   @retval EFI_SUCCESS          ChildHandle is a child of the ControllerHandle.
582   @retval EFI_UNSUPPORTED      ChildHandle is not a child of the
583                                ControllerHandle.
584 
585 **/
586 EFI_STATUS
587 EFIAPI
EfiTestChildHandle(IN CONST EFI_HANDLE ControllerHandle,IN CONST EFI_HANDLE ChildHandle,IN CONST EFI_GUID * ProtocolGuid)588 EfiTestChildHandle (
589   IN CONST EFI_HANDLE       ControllerHandle,
590   IN CONST EFI_HANDLE       ChildHandle,
591   IN CONST EFI_GUID         *ProtocolGuid
592   )
593 {
594   EFI_STATUS                            Status;
595   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
596   UINTN                                 EntryCount;
597   UINTN                                 Index;
598 
599   ASSERT (ProtocolGuid != NULL);
600 
601   //
602   // Retrieve the list of agents that are consuming the specific protocol
603   // on ControllerHandle.
604   //
605   Status = gBS->OpenProtocolInformation (
606                   ControllerHandle,
607                   (EFI_GUID *) ProtocolGuid,
608                   &OpenInfoBuffer,
609                   &EntryCount
610                   );
611   if (EFI_ERROR (Status)) {
612     return EFI_UNSUPPORTED;
613   }
614 
615   //
616   // Inspect if ChildHandle is one of the agents.
617   //
618   Status = EFI_UNSUPPORTED;
619   for (Index = 0; Index < EntryCount; Index++) {
620     if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
621         (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
622       Status = EFI_SUCCESS;
623       break;
624     }
625   }
626 
627   FreePool (OpenInfoBuffer);
628   return Status;
629 }
630 
631 /**
632   This function looks up a Unicode string in UnicodeStringTable.
633 
634   If Language is a member of SupportedLanguages and a Unicode string is found in
635   UnicodeStringTable that matches the language code specified by Language, then it
636   is returned in UnicodeString.
637 
638   @param  Language                A pointer to the ISO 639-2 language code for the
639                                   Unicode string to look up and return.
640   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
641                                   that the Unicode string table supports.  Language
642                                   must be a member of this set.
643   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
644   @param  UnicodeString           A pointer to the Unicode string from UnicodeStringTable
645                                   that matches the language specified by Language.
646 
647   @retval EFI_SUCCESS             The Unicode string that matches the language
648                                   specified by Language was found
649                                   in the table of Unicode strings UnicodeStringTable,
650                                   and it was returned in UnicodeString.
651   @retval EFI_INVALID_PARAMETER   Language is NULL.
652   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
653   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
654   @retval EFI_UNSUPPORTED         UnicodeStringTable is NULL.
655   @retval EFI_UNSUPPORTED         The language specified by Language is not a
656                                   member of SupportedLanguages.
657   @retval EFI_UNSUPPORTED         The language specified by Language is not
658                                   supported by UnicodeStringTable.
659 
660 **/
661 EFI_STATUS
662 EFIAPI
LookupUnicodeString(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN CONST EFI_UNICODE_STRING_TABLE * UnicodeStringTable,OUT CHAR16 ** UnicodeString)663 LookupUnicodeString (
664   IN CONST CHAR8                     *Language,
665   IN CONST CHAR8                     *SupportedLanguages,
666   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
667   OUT CHAR16                         **UnicodeString
668   )
669 {
670   //
671   // Make sure the parameters are valid
672   //
673   if (Language == NULL || UnicodeString == NULL) {
674     return EFI_INVALID_PARAMETER;
675   }
676 
677   //
678   // If there are no supported languages, or the Unicode String Table is empty, then the
679   // Unicode String specified by Language is not supported by this Unicode String Table
680   //
681   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
682     return EFI_UNSUPPORTED;
683   }
684 
685   //
686   // Make sure Language is in the set of Supported Languages
687   //
688   while (*SupportedLanguages != 0) {
689     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
690 
691       //
692       // Search the Unicode String Table for the matching Language specifier
693       //
694       while (UnicodeStringTable->Language != NULL) {
695         if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
696 
697           //
698           // A matching string was found, so return it
699           //
700           *UnicodeString = UnicodeStringTable->UnicodeString;
701           return EFI_SUCCESS;
702         }
703 
704         UnicodeStringTable++;
705       }
706 
707       return EFI_UNSUPPORTED;
708     }
709 
710     SupportedLanguages += 3;
711   }
712 
713   return EFI_UNSUPPORTED;
714 }
715 
716 
717 
718 /**
719   This function looks up a Unicode string in UnicodeStringTable.
720 
721   If Language is a member of SupportedLanguages and a Unicode string is found in
722   UnicodeStringTable that matches the language code specified by Language, then
723   it is returned in UnicodeString.
724 
725   @param  Language             A pointer to an ASCII string containing the ISO 639-2 or the
726                                RFC 4646 language code for the Unicode string to look up and
727                                return. If Iso639Language is TRUE, then this ASCII string is
728                                not assumed to be Null-terminated, and only the first three
729                                characters are used. If Iso639Language is FALSE, then this ASCII
730                                string must be Null-terminated.
731   @param  SupportedLanguages   A pointer to a Null-terminated ASCII string that contains a
732                                set of ISO 639-2 or RFC 4646 language codes that the Unicode
733                                string table supports.  Language must be a member of this set.
734                                If Iso639Language is TRUE, then this string contains one or more
735                                ISO 639-2 language codes with no separator characters. If Iso639Language
736                                is FALSE, then is string contains one or more RFC 4646 language
737                                codes separated by ';'.
738   @param  UnicodeStringTable   A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
739                                is defined in "Related Definitions".
740   @param  UnicodeString        A pointer to the Null-terminated Unicode string from UnicodeStringTable
741                                that matches the language specified by Language.
742   @param  Iso639Language       Specifies the supported language code format. If it is TRUE, then
743                                Language and SupportedLanguages follow ISO 639-2 language code format.
744                                Otherwise, they follow RFC 4646 language code format.
745 
746 
747   @retval  EFI_SUCCESS            The Unicode string that matches the language specified by Language
748                                   was found in the table of Unicode strings UnicodeStringTable, and
749                                   it was returned in UnicodeString.
750   @retval  EFI_INVALID_PARAMETER  Language is NULL.
751   @retval  EFI_INVALID_PARAMETER  UnicodeString is NULL.
752   @retval  EFI_UNSUPPORTED        SupportedLanguages is NULL.
753   @retval  EFI_UNSUPPORTED        UnicodeStringTable is NULL.
754   @retval  EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
755   @retval  EFI_UNSUPPORTED        The language specified by Language is not supported by UnicodeStringTable.
756 
757 **/
758 EFI_STATUS
759 EFIAPI
LookupUnicodeString2(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN CONST EFI_UNICODE_STRING_TABLE * UnicodeStringTable,OUT CHAR16 ** UnicodeString,IN BOOLEAN Iso639Language)760 LookupUnicodeString2 (
761   IN CONST CHAR8                     *Language,
762   IN CONST CHAR8                     *SupportedLanguages,
763   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
764   OUT CHAR16                         **UnicodeString,
765   IN BOOLEAN                         Iso639Language
766   )
767 {
768   BOOLEAN   Found;
769   UINTN     Index;
770   CHAR8     *LanguageString;
771 
772   //
773   // Make sure the parameters are valid
774   //
775   if (Language == NULL || UnicodeString == NULL) {
776     return EFI_INVALID_PARAMETER;
777   }
778 
779   //
780   // If there are no supported languages, or the Unicode String Table is empty, then the
781   // Unicode String specified by Language is not supported by this Unicode String Table
782   //
783   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
784     return EFI_UNSUPPORTED;
785   }
786 
787   //
788   // Make sure Language is in the set of Supported Languages
789   //
790   Found = FALSE;
791   while (*SupportedLanguages != 0) {
792     if (Iso639Language) {
793       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
794         Found = TRUE;
795         break;
796       }
797       SupportedLanguages += 3;
798     } else {
799       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
800       if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
801         Found = TRUE;
802         break;
803       }
804       SupportedLanguages += Index;
805       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
806     }
807   }
808 
809   //
810   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
811   //
812   if (!Found) {
813     return EFI_UNSUPPORTED;
814   }
815 
816   //
817   // Search the Unicode String Table for the matching Language specifier
818   //
819   while (UnicodeStringTable->Language != NULL) {
820     LanguageString = UnicodeStringTable->Language;
821     while (0 != *LanguageString) {
822       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
823       if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {
824         *UnicodeString = UnicodeStringTable->UnicodeString;
825         return EFI_SUCCESS;
826       }
827       LanguageString += Index;
828       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);
829     }
830     UnicodeStringTable++;
831   }
832 
833   return EFI_UNSUPPORTED;
834 }
835 
836 
837 /**
838   This function adds a Unicode string to UnicodeStringTable.
839 
840   If Language is a member of SupportedLanguages then UnicodeString is added to
841   UnicodeStringTable.  New buffers are allocated for both Language and
842   UnicodeString.  The contents of Language and UnicodeString are copied into
843   these new buffers.  These buffers are automatically freed when
844   FreeUnicodeStringTable() is called.
845 
846   @param  Language                A pointer to the ISO 639-2 language code for the Unicode
847                                   string to add.
848   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
849                                   that the Unicode string table supports.
850                                   Language must be a member of this set.
851   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
852   @param  UnicodeString           A pointer to the Unicode string to add.
853 
854   @retval EFI_SUCCESS             The Unicode string that matches the language
855                                   specified by Language was found in the table of
856                                   Unicode strings UnicodeStringTable, and it was
857                                   returned in UnicodeString.
858   @retval EFI_INVALID_PARAMETER   Language is NULL.
859   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
860   @retval EFI_INVALID_PARAMETER   UnicodeString is an empty string.
861   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
862   @retval EFI_ALREADY_STARTED     A Unicode string with language Language is
863                                   already present in UnicodeStringTable.
864   @retval EFI_OUT_OF_RESOURCES    There is not enough memory to add another
865                                   Unicode string to UnicodeStringTable.
866   @retval EFI_UNSUPPORTED         The language specified by Language is not a
867                                   member of SupportedLanguages.
868 
869 **/
870 EFI_STATUS
871 EFIAPI
AddUnicodeString(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN EFI_UNICODE_STRING_TABLE ** UnicodeStringTable,IN CONST CHAR16 * UnicodeString)872 AddUnicodeString (
873   IN CONST CHAR8               *Language,
874   IN CONST CHAR8               *SupportedLanguages,
875   IN EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
876   IN CONST CHAR16              *UnicodeString
877   )
878 {
879   UINTN                     NumberOfEntries;
880   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
881   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
882   UINTN                     UnicodeStringLength;
883 
884   //
885   // Make sure the parameter are valid
886   //
887   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
888     return EFI_INVALID_PARAMETER;
889   }
890 
891   //
892   // If there are no supported languages, then a Unicode String can not be added
893   //
894   if (SupportedLanguages == NULL) {
895     return EFI_UNSUPPORTED;
896   }
897 
898   //
899   // If the Unicode String is empty, then a Unicode String can not be added
900   //
901   if (UnicodeString[0] == 0) {
902     return EFI_INVALID_PARAMETER;
903   }
904 
905   //
906   // Make sure Language is a member of SupportedLanguages
907   //
908   while (*SupportedLanguages != 0) {
909     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
910 
911       //
912       // Determine the size of the Unicode String Table by looking for a NULL Language entry
913       //
914       NumberOfEntries = 0;
915       if (*UnicodeStringTable != NULL) {
916         OldUnicodeStringTable = *UnicodeStringTable;
917         while (OldUnicodeStringTable->Language != NULL) {
918           if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
919             return EFI_ALREADY_STARTED;
920           }
921 
922           OldUnicodeStringTable++;
923           NumberOfEntries++;
924         }
925       }
926 
927       //
928       // Allocate space for a new Unicode String Table.  It must hold the current number of
929       // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
930       // marker
931       //
932       NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
933       if (NewUnicodeStringTable == NULL) {
934         return EFI_OUT_OF_RESOURCES;
935       }
936 
937       //
938       // If the current Unicode String Table contains any entries, then copy them to the
939       // newly allocated Unicode String Table.
940       //
941       if (*UnicodeStringTable != NULL) {
942         CopyMem (
943            NewUnicodeStringTable,
944            *UnicodeStringTable,
945            NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
946            );
947       }
948 
949       //
950       // Allocate space for a copy of the Language specifier
951       //
952       NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
953       if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
954         FreePool (NewUnicodeStringTable);
955         return EFI_OUT_OF_RESOURCES;
956       }
957 
958       //
959       // Compute the length of the Unicode String
960       //
961       for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
962         ;
963 
964       //
965       // Allocate space for a copy of the Unicode String
966       //
967       NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
968                                                               (UnicodeStringLength + 1) * sizeof (CHAR16),
969                                                               UnicodeString
970                                                               );
971       if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
972         FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
973         FreePool (NewUnicodeStringTable);
974         return EFI_OUT_OF_RESOURCES;
975       }
976 
977       //
978       // Mark the end of the Unicode String Table
979       //
980       NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
981       NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
982 
983       //
984       // Free the old Unicode String Table
985       //
986       if (*UnicodeStringTable != NULL) {
987         FreePool (*UnicodeStringTable);
988       }
989 
990       //
991       // Point UnicodeStringTable at the newly allocated Unicode String Table
992       //
993       *UnicodeStringTable = NewUnicodeStringTable;
994 
995       return EFI_SUCCESS;
996     }
997 
998     SupportedLanguages += 3;
999   }
1000 
1001   return EFI_UNSUPPORTED;
1002 }
1003 
1004 
1005 /**
1006   This function adds the Null-terminated Unicode string specified by UnicodeString
1007   to UnicodeStringTable.
1008 
1009   If Language is a member of SupportedLanguages then UnicodeString is added to
1010   UnicodeStringTable.  New buffers are allocated for both Language and UnicodeString.
1011   The contents of Language and UnicodeString are copied into these new buffers.
1012   These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called.
1013 
1014   @param  Language            A pointer to an ASCII string containing the ISO 639-2 or
1015                               the RFC 4646 language code for the Unicode string to add.
1016                               If Iso639Language is TRUE, then this ASCII string is not
1017                               assumed to be Null-terminated, and only the first three
1018                               chacters are used. If Iso639Language is FALSE, then this
1019                               ASCII string must be Null-terminated.
1020   @param  SupportedLanguages  A pointer to a Null-terminated ASCII string that contains
1021                               a set of ISO 639-2 or RFC 4646 language codes that the Unicode
1022                               string table supports.  Language must be a member of this set.
1023                               If Iso639Language is TRUE, then this string contains one or more
1024                               ISO 639-2 language codes with no separator characters.
1025                               If Iso639Language is FALSE, then is string contains one or more
1026                               RFC 4646 language codes separated by ';'.
1027   @param  UnicodeStringTable  A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
1028                               is defined in "Related Definitions".
1029   @param  UnicodeString       A pointer to the Unicode string to add.
1030   @param  Iso639Language      Specifies the supported language code format. If it is TRUE,
1031                               then Language and SupportedLanguages follow ISO 639-2 language code format.
1032                               Otherwise, they follow RFC 4646 language code format.
1033 
1034   @retval EFI_SUCCESS            The Unicode string that matches the language specified by
1035                                  Language was found in the table of Unicode strings UnicodeStringTable,
1036                                  and it was returned in UnicodeString.
1037   @retval EFI_INVALID_PARAMETER  Language is NULL.
1038   @retval EFI_INVALID_PARAMETER  UnicodeString is NULL.
1039   @retval EFI_INVALID_PARAMETER  UnicodeString is an empty string.
1040   @retval EFI_UNSUPPORTED        SupportedLanguages is NULL.
1041   @retval EFI_ALREADY_STARTED    A Unicode string with language Language is already present in
1042                                  UnicodeStringTable.
1043   @retval EFI_OUT_OF_RESOURCES   There is not enough memory to add another Unicode string UnicodeStringTable.
1044   @retval EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
1045 
1046 **/
1047 EFI_STATUS
1048 EFIAPI
AddUnicodeString2(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN EFI_UNICODE_STRING_TABLE ** UnicodeStringTable,IN CONST CHAR16 * UnicodeString,IN BOOLEAN Iso639Language)1049 AddUnicodeString2 (
1050   IN CONST CHAR8               *Language,
1051   IN CONST CHAR8               *SupportedLanguages,
1052   IN EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
1053   IN CONST CHAR16              *UnicodeString,
1054   IN BOOLEAN                   Iso639Language
1055   )
1056 {
1057   UINTN                     NumberOfEntries;
1058   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
1059   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
1060   UINTN                     UnicodeStringLength;
1061   BOOLEAN                   Found;
1062   UINTN                     Index;
1063   CHAR8                     *LanguageString;
1064 
1065   //
1066   // Make sure the parameter are valid
1067   //
1068   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
1069     return EFI_INVALID_PARAMETER;
1070   }
1071 
1072   //
1073   // If there are no supported languages, then a Unicode String can not be added
1074   //
1075   if (SupportedLanguages == NULL) {
1076     return EFI_UNSUPPORTED;
1077   }
1078 
1079   //
1080   // If the Unicode String is empty, then a Unicode String can not be added
1081   //
1082   if (UnicodeString[0] == 0) {
1083     return EFI_INVALID_PARAMETER;
1084   }
1085 
1086   //
1087   // Make sure Language is a member of SupportedLanguages
1088   //
1089   Found = FALSE;
1090   while (*SupportedLanguages != 0) {
1091     if (Iso639Language) {
1092       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
1093         Found = TRUE;
1094         break;
1095       }
1096       SupportedLanguages += 3;
1097     } else {
1098       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
1099       if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {
1100         Found = TRUE;
1101         break;
1102       }
1103       SupportedLanguages += Index;
1104       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
1105     }
1106   }
1107 
1108   //
1109   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
1110   //
1111   if (!Found) {
1112     return EFI_UNSUPPORTED;
1113   }
1114 
1115   //
1116   // Determine the size of the Unicode String Table by looking for a NULL Language entry
1117   //
1118   NumberOfEntries = 0;
1119   if (*UnicodeStringTable != NULL) {
1120     OldUnicodeStringTable = *UnicodeStringTable;
1121     while (OldUnicodeStringTable->Language != NULL) {
1122       LanguageString = OldUnicodeStringTable->Language;
1123 
1124       while (*LanguageString != 0) {
1125         for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
1126 
1127         if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
1128           return EFI_ALREADY_STARTED;
1129         }
1130         LanguageString += Index;
1131         for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);
1132       }
1133       OldUnicodeStringTable++;
1134       NumberOfEntries++;
1135     }
1136   }
1137 
1138   //
1139   // Allocate space for a new Unicode String Table.  It must hold the current number of
1140   // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
1141   // marker
1142   //
1143   NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
1144   if (NewUnicodeStringTable == NULL) {
1145     return EFI_OUT_OF_RESOURCES;
1146   }
1147 
1148   //
1149   // If the current Unicode String Table contains any entries, then copy them to the
1150   // newly allocated Unicode String Table.
1151   //
1152   if (*UnicodeStringTable != NULL) {
1153     CopyMem (
1154       NewUnicodeStringTable,
1155       *UnicodeStringTable,
1156       NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
1157       );
1158   }
1159 
1160   //
1161   // Allocate space for a copy of the Language specifier
1162   //
1163   NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);
1164   if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
1165     FreePool (NewUnicodeStringTable);
1166     return EFI_OUT_OF_RESOURCES;
1167   }
1168 
1169   //
1170   // Compute the length of the Unicode String
1171   //
1172   for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);
1173 
1174   //
1175   // Allocate space for a copy of the Unicode String
1176   //
1177   NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
1178   if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
1179     FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
1180     FreePool (NewUnicodeStringTable);
1181     return EFI_OUT_OF_RESOURCES;
1182   }
1183 
1184   //
1185   // Mark the end of the Unicode String Table
1186   //
1187   NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
1188   NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
1189 
1190   //
1191   // Free the old Unicode String Table
1192   //
1193   if (*UnicodeStringTable != NULL) {
1194     FreePool (*UnicodeStringTable);
1195   }
1196 
1197   //
1198   // Point UnicodeStringTable at the newly allocated Unicode String Table
1199   //
1200   *UnicodeStringTable = NewUnicodeStringTable;
1201 
1202   return EFI_SUCCESS;
1203 }
1204 
1205 /**
1206   This function frees the table of Unicode strings in UnicodeStringTable.
1207 
1208   If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
1209   Otherwise, each language code, and each Unicode string in the Unicode string
1210   table are freed, and EFI_SUCCESS is returned.
1211 
1212   @param  UnicodeStringTable  A pointer to the table of Unicode strings.
1213 
1214   @retval EFI_SUCCESS         The Unicode string table was freed.
1215 
1216 **/
1217 EFI_STATUS
1218 EFIAPI
FreeUnicodeStringTable(IN EFI_UNICODE_STRING_TABLE * UnicodeStringTable)1219 FreeUnicodeStringTable (
1220   IN EFI_UNICODE_STRING_TABLE  *UnicodeStringTable
1221   )
1222 {
1223   UINTN Index;
1224 
1225   //
1226   // If the Unicode String Table is NULL, then it is already freed
1227   //
1228   if (UnicodeStringTable == NULL) {
1229     return EFI_SUCCESS;
1230   }
1231 
1232   //
1233   // Loop through the Unicode String Table until we reach the end of table marker
1234   //
1235   for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
1236 
1237     //
1238     // Free the Language string from the Unicode String Table
1239     //
1240     FreePool (UnicodeStringTable[Index].Language);
1241 
1242     //
1243     // Free the Unicode String from the Unicode String Table
1244     //
1245     if (UnicodeStringTable[Index].UnicodeString != NULL) {
1246       FreePool (UnicodeStringTable[Index].UnicodeString);
1247     }
1248   }
1249 
1250   //
1251   // Free the Unicode String Table itself
1252   //
1253   FreePool (UnicodeStringTable);
1254 
1255   return EFI_SUCCESS;
1256 }
1257 
1258 #ifndef DISABLE_NEW_DEPRECATED_INTERFACES
1259 
1260 /**
1261   [ATTENTION] This function will be deprecated for security reason.
1262 
1263   Returns a pointer to an allocated buffer that contains the contents of a
1264   variable retrieved through the UEFI Runtime Service GetVariable().  The
1265   returned buffer is allocated using AllocatePool().  The caller is responsible
1266   for freeing this buffer with FreePool().
1267 
1268   If Name is NULL, then ASSERT().
1269   If Guid is NULL, then ASSERT().
1270 
1271   @param[in]  Name  The pointer to a Null-terminated Unicode string.
1272   @param[in]  Guid  The pointer to an EFI_GUID structure
1273 
1274   @retval NULL   The variable could not be retrieved.
1275   @retval NULL   There are not enough resources available for the variable contents.
1276   @retval Other  A pointer to allocated buffer containing the variable contents.
1277 
1278 **/
1279 VOID *
1280 EFIAPI
GetVariable(IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid)1281 GetVariable (
1282   IN CONST CHAR16    *Name,
1283   IN CONST EFI_GUID  *Guid
1284   )
1285 {
1286   EFI_STATUS  Status;
1287   UINTN       Size;
1288   VOID        *Value;
1289 
1290   ASSERT (Name != NULL);
1291   ASSERT (Guid != NULL);
1292 
1293   //
1294   // Try to get the variable size.
1295   //
1296   Value = NULL;
1297   Size = 0;
1298   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
1299   if (Status != EFI_BUFFER_TOO_SMALL) {
1300     return NULL;
1301   }
1302 
1303   //
1304   // Allocate buffer to get the variable.
1305   //
1306   Value = AllocatePool (Size);
1307   if (Value == NULL) {
1308     return NULL;
1309   }
1310 
1311   //
1312   // Get the variable data.
1313   //
1314   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
1315   if (EFI_ERROR (Status)) {
1316     FreePool(Value);
1317     return NULL;
1318   }
1319 
1320   return Value;
1321 }
1322 
1323 /**
1324   [ATTENTION] This function will be deprecated for security reason.
1325 
1326   Returns a pointer to an allocated buffer that contains the contents of a
1327   variable retrieved through the UEFI Runtime Service GetVariable().  This
1328   function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
1329   The returned buffer is allocated using AllocatePool().  The caller is
1330   responsible for freeing this buffer with FreePool().
1331 
1332   If Name is NULL, then ASSERT().
1333 
1334   @param[in]  Name  The pointer to a Null-terminated Unicode string.
1335 
1336   @retval NULL   The variable could not be retrieved.
1337   @retval NULL   There are not enough resources available for the variable contents.
1338   @retval Other  A pointer to allocated buffer containing the variable contents.
1339 
1340 **/
1341 VOID *
1342 EFIAPI
GetEfiGlobalVariable(IN CONST CHAR16 * Name)1343 GetEfiGlobalVariable (
1344   IN CONST CHAR16  *Name
1345   )
1346 {
1347   return GetVariable (Name, &gEfiGlobalVariableGuid);
1348 }
1349 #endif
1350 
1351 /**
1352   Returns the status whether get the variable success. The function retrieves
1353   variable  through the UEFI Runtime Service GetVariable().  The
1354   returned buffer is allocated using AllocatePool().  The caller is responsible
1355   for freeing this buffer with FreePool().
1356 
1357   If Name  is NULL, then ASSERT().
1358   If Guid  is NULL, then ASSERT().
1359   If Value is NULL, then ASSERT().
1360 
1361   @param[in]  Name  The pointer to a Null-terminated Unicode string.
1362   @param[in]  Guid  The pointer to an EFI_GUID structure
1363   @param[out] Value The buffer point saved the variable info.
1364   @param[out] Size  The buffer size of the variable.
1365 
1366   @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
1367   @return EFI_SUCCESS               Find the specified variable.
1368   @return Others Errors             Return errors from call to gRT->GetVariable.
1369 
1370 **/
1371 EFI_STATUS
1372 EFIAPI
GetVariable2(IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid,OUT VOID ** Value,OUT UINTN * Size OPTIONAL)1373 GetVariable2 (
1374   IN CONST CHAR16    *Name,
1375   IN CONST EFI_GUID  *Guid,
1376   OUT VOID           **Value,
1377   OUT UINTN          *Size OPTIONAL
1378   )
1379 {
1380   EFI_STATUS  Status;
1381   UINTN       BufferSize;
1382 
1383   ASSERT (Name != NULL && Guid != NULL && Value != NULL);
1384 
1385   //
1386   // Try to get the variable size.
1387   //
1388   BufferSize = 0;
1389   *Value     = NULL;
1390   if (Size != NULL) {
1391     *Size  = 0;
1392   }
1393 
1394   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
1395   if (Status != EFI_BUFFER_TOO_SMALL) {
1396     return Status;
1397   }
1398 
1399   //
1400   // Allocate buffer to get the variable.
1401   //
1402   *Value = AllocatePool (BufferSize);
1403   ASSERT (*Value != NULL);
1404   if (*Value == NULL) {
1405     return EFI_OUT_OF_RESOURCES;
1406   }
1407 
1408   //
1409   // Get the variable data.
1410   //
1411   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
1412   if (EFI_ERROR (Status)) {
1413     FreePool(*Value);
1414     *Value = NULL;
1415   }
1416 
1417   if (Size != NULL) {
1418     *Size = BufferSize;
1419   }
1420 
1421   return Status;
1422 }
1423 
1424 /**
1425   Returns a pointer to an allocated buffer that contains the contents of a
1426   variable retrieved through the UEFI Runtime Service GetVariable().  This
1427   function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
1428   The returned buffer is allocated using AllocatePool().  The caller is
1429   responsible for freeing this buffer with FreePool().
1430 
1431   If Name is NULL, then ASSERT().
1432   If Value is NULL, then ASSERT().
1433 
1434   @param[in]  Name  The pointer to a Null-terminated Unicode string.
1435   @param[out] Value The buffer point saved the variable info.
1436   @param[out] Size  The buffer size of the variable.
1437 
1438   @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
1439   @return EFI_SUCCESS               Find the specified variable.
1440   @return Others Errors             Return errors from call to gRT->GetVariable.
1441 
1442 **/
1443 EFI_STATUS
1444 EFIAPI
GetEfiGlobalVariable2(IN CONST CHAR16 * Name,OUT VOID ** Value,OUT UINTN * Size OPTIONAL)1445 GetEfiGlobalVariable2 (
1446   IN CONST CHAR16    *Name,
1447   OUT VOID           **Value,
1448   OUT UINTN          *Size OPTIONAL
1449   )
1450 {
1451   return GetVariable2 (Name, &gEfiGlobalVariableGuid, Value, Size);
1452 }
1453 
1454 /**
1455   Returns a pointer to an allocated buffer that contains the best matching language
1456   from a set of supported languages.
1457 
1458   This function supports both ISO 639-2 and RFC 4646 language codes, but language
1459   code types may not be mixed in a single call to this function.  The language
1460   code returned is allocated using AllocatePool().  The caller is responsible for
1461   freeing the allocated buffer using FreePool().  This function supports a variable
1462   argument list that allows the caller to pass in a prioritized list of language
1463   codes to test against all the language codes in SupportedLanguages.
1464 
1465   If SupportedLanguages is NULL, then ASSERT().
1466 
1467   @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
1468                                   contains a set of language codes in the format
1469                                   specified by Iso639Language.
1470   @param[in]  Iso639Language      If TRUE, then all language codes are assumed to be
1471                                   in ISO 639-2 format.  If FALSE, then all language
1472                                   codes are assumed to be in RFC 4646 language format
1473   @param[in]  ...                 A variable argument list that contains pointers to
1474                                   Null-terminated ASCII strings that contain one or more
1475                                   language codes in the format specified by Iso639Language.
1476                                   The first language code from each of these language
1477                                   code lists is used to determine if it is an exact or
1478                                   close match to any of the language codes in
1479                                   SupportedLanguages.  Close matches only apply to RFC 4646
1480                                   language codes, and the matching algorithm from RFC 4647
1481                                   is used to determine if a close match is present.  If
1482                                   an exact or close match is found, then the matching
1483                                   language code from SupportedLanguages is returned.  If
1484                                   no matches are found, then the next variable argument
1485                                   parameter is evaluated.  The variable argument list
1486                                   is terminated by a NULL.
1487 
1488   @retval NULL   The best matching language could not be found in SupportedLanguages.
1489   @retval NULL   There are not enough resources available to return the best matching
1490                  language.
1491   @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
1492                  language in SupportedLanguages.
1493 
1494 **/
1495 CHAR8 *
1496 EFIAPI
GetBestLanguage(IN CONST CHAR8 * SupportedLanguages,IN BOOLEAN Iso639Language,...)1497 GetBestLanguage (
1498   IN CONST CHAR8  *SupportedLanguages,
1499   IN BOOLEAN      Iso639Language,
1500   ...
1501   )
1502 {
1503   VA_LIST      Args;
1504   CHAR8        *Language;
1505   UINTN        CompareLength;
1506   UINTN        LanguageLength;
1507   CONST CHAR8  *Supported;
1508   CHAR8        *BestLanguage;
1509 
1510   ASSERT (SupportedLanguages != NULL);
1511 
1512   VA_START (Args, Iso639Language);
1513   while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1514     //
1515     // Default to ISO 639-2 mode
1516     //
1517     CompareLength  = 3;
1518     LanguageLength = MIN (3, AsciiStrLen (Language));
1519 
1520     //
1521     // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1522     //
1523     if (!Iso639Language) {
1524       for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
1525     }
1526 
1527     //
1528     // Trim back the length of Language used until it is empty
1529     //
1530     while (LanguageLength > 0) {
1531       //
1532       // Loop through all language codes in SupportedLanguages
1533       //
1534       for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1535         //
1536         // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1537         //
1538         if (!Iso639Language) {
1539           //
1540           // Skip ';' characters in Supported
1541           //
1542           for (; *Supported != '\0' && *Supported == ';'; Supported++);
1543           //
1544           // Determine the length of the next language code in Supported
1545           //
1546           for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
1547           //
1548           // If Language is longer than the Supported, then skip to the next language
1549           //
1550           if (LanguageLength > CompareLength) {
1551             continue;
1552           }
1553         }
1554         //
1555         // See if the first LanguageLength characters in Supported match Language
1556         //
1557         if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1558           VA_END (Args);
1559           //
1560           // Allocate, copy, and return the best matching language code from SupportedLanguages
1561           //
1562           BestLanguage = AllocateZeroPool (CompareLength + 1);
1563           if (BestLanguage == NULL) {
1564             return NULL;
1565           }
1566           return CopyMem (BestLanguage, Supported, CompareLength);
1567         }
1568       }
1569 
1570       if (Iso639Language) {
1571         //
1572         // If ISO 639 mode, then each language can only be tested once
1573         //
1574         LanguageLength = 0;
1575       } else {
1576         //
1577         // If RFC 4646 mode, then trim Language from the right to the next '-' character
1578         //
1579         for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
1580       }
1581     }
1582   }
1583   VA_END (Args);
1584 
1585   //
1586   // No matches were found
1587   //
1588   return NULL;
1589 }
1590 
1591 /**
1592   An empty function to pass error checking of CreateEventEx ().
1593 
1594   This empty function ensures that EVT_NOTIFY_SIGNAL_ALL is error
1595   checked correctly since it is now mapped into CreateEventEx() in UEFI 2.0.
1596 
1597   @param  Event                 Event whose notification function is being invoked.
1598   @param  Context               The pointer to the notification function's context,
1599                                 which is implementation-dependent.
1600 
1601 **/
1602 VOID
1603 EFIAPI
InternalEmptyFunction(IN EFI_EVENT Event,IN VOID * Context)1604 InternalEmptyFunction (
1605   IN EFI_EVENT                Event,
1606   IN VOID                     *Context
1607   )
1608 {
1609 }
1610