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