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 - 2018, Intel Corporation. All rights reserved.<BR>
9   SPDX-License-Identifier: BSD-2-Clause-Patent
10 
11 **/
12 
13 
14 #include "UefiLibInternal.h"
15 
16 /**
17   Compare whether two names of languages are identical.
18 
19   @param  Language1 Name of language 1.
20   @param  Language2 Name of language 2.
21 
22   @retval TRUE      Language 1 and language 2 are the same.
23   @retval FALSE     Language 1 and language 2 are not the same.
24 
25 **/
26 BOOLEAN
CompareIso639LanguageCode(IN CONST CHAR8 * Language1,IN CONST CHAR8 * Language2)27 CompareIso639LanguageCode (
28   IN CONST CHAR8  *Language1,
29   IN CONST CHAR8  *Language2
30   )
31 {
32   UINT32  Name1;
33   UINT32  Name2;
34 
35   Name1 = ReadUnaligned24 ((CONST UINT32 *) Language1);
36   Name2 = ReadUnaligned24 ((CONST UINT32 *) Language2);
37 
38   return (BOOLEAN) (Name1 == Name2);
39 }
40 
41 /**
42   Retrieves a pointer to the system configuration table from the EFI System Table
43   based on a specified GUID.
44 
45   This function searches the list of configuration tables stored in the EFI System Table
46   for a table with a GUID that matches TableGuid.  If a match is found, then a pointer to
47   the configuration table is returned in Table., and EFI_SUCCESS is returned. If a matching GUID
48   is not found, then EFI_NOT_FOUND is returned.
49   If TableGuid is NULL, then ASSERT().
50   If Table is NULL, then ASSERT().
51 
52   @param  TableGuid       Pointer to table's GUID type..
53   @param  Table           Pointer to the table associated with TableGuid in the EFI System Table.
54 
55   @retval EFI_SUCCESS     A configuration table matching TableGuid was found.
56   @retval EFI_NOT_FOUND   A configuration table matching TableGuid could not be found.
57 
58 **/
59 EFI_STATUS
60 EFIAPI
EfiGetSystemConfigurationTable(IN EFI_GUID * TableGuid,OUT VOID ** Table)61 EfiGetSystemConfigurationTable (
62   IN  EFI_GUID  *TableGuid,
63   OUT VOID      **Table
64   )
65 {
66   EFI_SYSTEM_TABLE  *SystemTable;
67   UINTN             Index;
68 
69   ASSERT (TableGuid != NULL);
70   ASSERT (Table != NULL);
71 
72   SystemTable = gST;
73   *Table = NULL;
74   for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
75     if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {
76       *Table = SystemTable->ConfigurationTable[Index].VendorTable;
77       return EFI_SUCCESS;
78     }
79   }
80 
81   return EFI_NOT_FOUND;
82 }
83 
84 /**
85   Creates and returns a notification event and registers that event with all the protocol
86   instances specified by ProtocolGuid.
87 
88   This function causes the notification function to be executed for every protocol of type
89   ProtocolGuid instance that exists in the system when this function is invoked. If there are
90   no instances of ProtocolGuid in the handle database at the time this function is invoked,
91   then the notification function is still executed one time. In addition, every time a protocol
92   of type ProtocolGuid instance is installed or reinstalled, the notification function is also
93   executed. This function returns the notification event that was created.
94   If ProtocolGuid is NULL, then ASSERT().
95   If NotifyTpl is not a legal TPL value, then ASSERT().
96   If NotifyFunction is NULL, then ASSERT().
97   If Registration is NULL, then ASSERT().
98 
99 
100   @param  ProtocolGuid    Supplies GUID of the protocol upon whose installation the event is fired.
101   @param  NotifyTpl       Supplies the task priority level of the event notifications.
102   @param  NotifyFunction  Supplies the function to notify when the event is signaled.
103   @param  NotifyContext   The context parameter to pass to NotifyFunction.
104   @param  Registration    A pointer to a memory location to receive the registration value.
105                           This value is passed to LocateHandle() to obtain new handles that
106                           have been added that support the ProtocolGuid-specified protocol.
107 
108   @return The notification event that was created.
109 
110 **/
111 EFI_EVENT
112 EFIAPI
EfiCreateProtocolNotifyEvent(IN EFI_GUID * ProtocolGuid,IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,IN VOID * NotifyContext,OPTIONAL OUT VOID ** Registration)113 EfiCreateProtocolNotifyEvent(
114   IN  EFI_GUID          *ProtocolGuid,
115   IN  EFI_TPL           NotifyTpl,
116   IN  EFI_EVENT_NOTIFY  NotifyFunction,
117   IN  VOID              *NotifyContext,  OPTIONAL
118   OUT VOID              **Registration
119   )
120 {
121   EFI_STATUS  Status;
122   EFI_EVENT   Event;
123 
124   ASSERT (ProtocolGuid != NULL);
125   ASSERT (NotifyFunction != NULL);
126   ASSERT (Registration != NULL);
127 
128   //
129   // Create the event
130   //
131 
132   Status = gBS->CreateEvent (
133                   EVT_NOTIFY_SIGNAL,
134                   NotifyTpl,
135                   NotifyFunction,
136                   NotifyContext,
137                   &Event
138                   );
139   ASSERT_EFI_ERROR (Status);
140 
141   //
142   // Register for protocol notifications on this event
143   //
144 
145   Status = gBS->RegisterProtocolNotify (
146                   ProtocolGuid,
147                   Event,
148                   Registration
149                   );
150 
151   ASSERT_EFI_ERROR (Status);
152 
153   //
154   // Kick the event so we will perform an initial pass of
155   // current installed drivers
156   //
157 
158   gBS->SignalEvent (Event);
159   return Event;
160 }
161 
162 /**
163   Creates a named event that can be signaled with EfiNamedEventSignal().
164 
165   This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.
166   This event is signaled with EfiNamedEventSignal(). This provides the ability for one or more
167   listeners on the same event named by the GUID specified by Name.
168   If Name is NULL, then ASSERT().
169   If NotifyTpl is not a legal TPL value, then ASSERT().
170   If NotifyFunction is NULL, then ASSERT().
171 
172   @param  Name                  Supplies GUID name of the event.
173   @param  NotifyTpl             Supplies the task priority level of the event notifications.
174   @param  NotifyFunction        Supplies the function to notify when the event is signaled.
175   @param  NotifyContext         The context parameter to pass to NotifyFunction.
176   @param  Registration          A pointer to a memory location to receive the registration value.
177 
178   @retval EFI_SUCCESS           A named event was created.
179   @retval EFI_OUT_OF_RESOURCES  There are not enough resource to create the named event.
180 
181 **/
182 EFI_STATUS
183 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)184 EfiNamedEventListen (
185   IN CONST EFI_GUID    *Name,
186   IN EFI_TPL           NotifyTpl,
187   IN EFI_EVENT_NOTIFY  NotifyFunction,
188   IN CONST VOID        *NotifyContext,  OPTIONAL
189   OUT VOID             *Registration OPTIONAL
190   )
191 {
192   EFI_STATUS  Status;
193   EFI_EVENT   Event;
194   VOID        *RegistrationLocal;
195 
196   ASSERT (Name != NULL);
197   ASSERT (NotifyFunction != NULL);
198   ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
199 
200   //
201   // Create event
202   //
203   Status = gBS->CreateEvent (
204                   EVT_NOTIFY_SIGNAL,
205                   NotifyTpl,
206                   NotifyFunction,
207                   (VOID *) NotifyContext,
208                   &Event
209                   );
210   ASSERT_EFI_ERROR (Status);
211 
212   //
213   // The Registration is not optional to RegisterProtocolNotify().
214   // To make it optional to EfiNamedEventListen(), may need to substitute with a local.
215   //
216   if (Registration != NULL) {
217     RegistrationLocal = Registration;
218   } else {
219     RegistrationLocal = &RegistrationLocal;
220   }
221 
222   //
223   // Register for an installation of protocol interface
224   //
225 
226   Status = gBS->RegisterProtocolNotify (
227                   (EFI_GUID *) Name,
228                   Event,
229                   RegistrationLocal
230                   );
231   ASSERT_EFI_ERROR (Status);
232 
233   return Status;
234 }
235 
236 /**
237   Signals a named event created with EfiNamedEventListen().
238 
239   This function signals the named event specified by Name. The named event must have been
240   created with EfiNamedEventListen().
241   If Name is NULL, then ASSERT().
242 
243   @param  Name                  Supplies GUID name of the event.
244 
245   @retval EFI_SUCCESS           A named event was signaled.
246   @retval EFI_OUT_OF_RESOURCES  There are not enough resource to signal the named event.
247 
248 **/
249 EFI_STATUS
250 EFIAPI
EfiNamedEventSignal(IN CONST EFI_GUID * Name)251 EfiNamedEventSignal (
252   IN CONST EFI_GUID  *Name
253   )
254 {
255   EFI_STATUS  Status;
256   EFI_HANDLE  Handle;
257 
258   ASSERT(Name != NULL);
259 
260   Handle = NULL;
261   Status = gBS->InstallProtocolInterface (
262                   &Handle,
263                   (EFI_GUID *) Name,
264                   EFI_NATIVE_INTERFACE,
265                   NULL
266                   );
267   ASSERT_EFI_ERROR (Status);
268 
269   Status = gBS->UninstallProtocolInterface (
270                   Handle,
271                   (EFI_GUID *) Name,
272                   NULL
273                   );
274   ASSERT_EFI_ERROR (Status);
275 
276   return Status;
277 }
278 
279 /**
280   Signals an event group by placing a new event in the group temporarily and
281   signaling it.
282 
283   @param[in] EventGroup          Supplies the unique identifier of the event
284                                  group to signal.
285 
286   @retval EFI_SUCCESS            The event group was signaled successfully.
287   @retval EFI_INVALID_PARAMETER  EventGroup is NULL.
288   @return                        Error codes that report problems about event
289                                  creation or signaling.
290 **/
291 EFI_STATUS
292 EFIAPI
EfiEventGroupSignal(IN CONST EFI_GUID * EventGroup)293 EfiEventGroupSignal (
294   IN CONST EFI_GUID *EventGroup
295   )
296 {
297   EFI_STATUS Status;
298   EFI_EVENT  Event;
299 
300   if (EventGroup == NULL) {
301     return EFI_INVALID_PARAMETER;
302   }
303 
304   Status = gBS->CreateEventEx (
305                   EVT_NOTIFY_SIGNAL,
306                   TPL_CALLBACK,
307                   EfiEventEmptyFunction,
308                   NULL,
309                   EventGroup,
310                   &Event
311                   );
312   if (EFI_ERROR (Status)) {
313     return Status;
314   }
315 
316   Status = gBS->SignalEvent (Event);
317   gBS->CloseEvent (Event);
318 
319   return Status;
320 }
321 
322 /**
323   An empty function that can be used as NotifyFunction parameter of
324   CreateEvent() or CreateEventEx().
325 
326   @param Event              Event whose notification function is being invoked.
327   @param Context            The pointer to the notification function's context,
328                             which is implementation-dependent.
329 
330 **/
331 VOID
332 EFIAPI
EfiEventEmptyFunction(IN EFI_EVENT Event,IN VOID * Context)333 EfiEventEmptyFunction (
334   IN EFI_EVENT              Event,
335   IN VOID                   *Context
336   )
337 {
338 }
339 
340 /**
341   Returns the current TPL.
342 
343   This function returns the current TPL.  There is no EFI service to directly
344   retrieve the current TPL. Instead, the RaiseTPL() function is used to raise
345   the TPL to TPL_HIGH_LEVEL.  This will return the current TPL.  The TPL level
346   can then immediately be restored back to the current TPL level with a call
347   to RestoreTPL().
348 
349   @return The current TPL.
350 
351 **/
352 EFI_TPL
353 EFIAPI
EfiGetCurrentTpl(VOID)354 EfiGetCurrentTpl (
355   VOID
356   )
357 {
358   EFI_TPL Tpl;
359 
360   Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
361   gBS->RestoreTPL (Tpl);
362 
363   return Tpl;
364 }
365 
366 
367 /**
368   Initializes a basic mutual exclusion lock.
369 
370   This function initializes a basic mutual exclusion lock to the released state
371   and returns the lock.  Each lock provides mutual exclusion access at its task
372   priority level.  Since there is no preemption or multiprocessor support in EFI,
373   acquiring the lock only consists of raising to the locks TPL.
374   If Lock is NULL, then ASSERT().
375   If Priority is not a valid TPL value, then ASSERT().
376 
377   @param  Lock       A pointer to the lock data structure to initialize.
378   @param  Priority   EFI TPL associated with the lock.
379 
380   @return The lock.
381 
382 **/
383 EFI_LOCK *
384 EFIAPI
EfiInitializeLock(IN OUT EFI_LOCK * Lock,IN EFI_TPL Priority)385 EfiInitializeLock (
386   IN OUT EFI_LOCK  *Lock,
387   IN EFI_TPL        Priority
388   )
389 {
390   ASSERT (Lock != NULL);
391   ASSERT (Priority <= TPL_HIGH_LEVEL);
392 
393   Lock->Tpl       = Priority;
394   Lock->OwnerTpl  = TPL_APPLICATION;
395   Lock->Lock      = EfiLockReleased ;
396   return Lock;
397 }
398 
399 /**
400   Acquires ownership of a lock.
401 
402   This function raises the system's current task priority level to the task
403   priority level of the mutual exclusion lock.  Then, it places the lock in the
404   acquired state.
405   If Lock is NULL, then ASSERT().
406   If Lock is not initialized, then ASSERT().
407   If Lock is already in the acquired state, then ASSERT().
408 
409   @param  Lock              A pointer to the lock to acquire.
410 
411 **/
412 VOID
413 EFIAPI
EfiAcquireLock(IN EFI_LOCK * Lock)414 EfiAcquireLock (
415   IN EFI_LOCK  *Lock
416   )
417 {
418   ASSERT (Lock != NULL);
419   ASSERT (Lock->Lock == EfiLockReleased);
420 
421   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
422   Lock->Lock     = EfiLockAcquired;
423 }
424 
425 /**
426   Acquires ownership of a lock.
427 
428   This function raises the system's current task priority level to the task priority
429   level of the mutual exclusion lock.  Then, it attempts to place the lock in the acquired state.
430   If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
431   Otherwise, EFI_SUCCESS is returned.
432   If Lock is NULL, then ASSERT().
433   If Lock is not initialized, then ASSERT().
434 
435   @param  Lock              A pointer to the lock to acquire.
436 
437   @retval EFI_SUCCESS       The lock was acquired.
438   @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
439 
440 **/
441 EFI_STATUS
442 EFIAPI
EfiAcquireLockOrFail(IN EFI_LOCK * Lock)443 EfiAcquireLockOrFail (
444   IN EFI_LOCK  *Lock
445   )
446 {
447 
448   ASSERT (Lock != NULL);
449   ASSERT (Lock->Lock != EfiLockUninitialized);
450 
451   if (Lock->Lock == EfiLockAcquired) {
452     //
453     // Lock is already owned, so bail out
454     //
455     return EFI_ACCESS_DENIED;
456   }
457 
458   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
459 
460   Lock->Lock = EfiLockAcquired;
461 
462   return EFI_SUCCESS;
463 }
464 
465 /**
466   Releases ownership of a lock.
467 
468   This function transitions a mutual exclusion lock from the acquired state to
469   the released state, and restores the system's task priority level to its
470   previous level.
471   If Lock is NULL, then ASSERT().
472   If Lock is not initialized, then ASSERT().
473   If Lock is already in the released state, then ASSERT().
474 
475   @param  Lock  A pointer to the lock to release.
476 
477 **/
478 VOID
479 EFIAPI
EfiReleaseLock(IN EFI_LOCK * Lock)480 EfiReleaseLock (
481   IN EFI_LOCK  *Lock
482   )
483 {
484   EFI_TPL Tpl;
485 
486   ASSERT (Lock != NULL);
487   ASSERT (Lock->Lock == EfiLockAcquired);
488 
489   Tpl = Lock->OwnerTpl;
490 
491   Lock->Lock = EfiLockReleased;
492 
493   gBS->RestoreTPL (Tpl);
494 }
495 
496 /**
497   Tests whether a controller handle is being managed by a specific driver.
498 
499   This function tests whether the driver specified by DriverBindingHandle is
500   currently managing the controller specified by ControllerHandle.  This test
501   is performed by evaluating if the the protocol specified by ProtocolGuid is
502   present on ControllerHandle and is was opened by DriverBindingHandle with an
503   attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
504   If ProtocolGuid is NULL, then ASSERT().
505 
506   @param  ControllerHandle     A handle for a controller to test.
507   @param  DriverBindingHandle  Specifies the driver binding handle for the
508                                driver.
509   @param  ProtocolGuid         Specifies the protocol that the driver specified
510                                by DriverBindingHandle opens in its Start()
511                                function.
512 
513   @retval EFI_SUCCESS          ControllerHandle is managed by the driver
514                                specified by DriverBindingHandle.
515   @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
516                                specified by DriverBindingHandle.
517 
518 **/
519 EFI_STATUS
520 EFIAPI
EfiTestManagedDevice(IN CONST EFI_HANDLE ControllerHandle,IN CONST EFI_HANDLE DriverBindingHandle,IN CONST EFI_GUID * ProtocolGuid)521 EfiTestManagedDevice (
522   IN CONST EFI_HANDLE       ControllerHandle,
523   IN CONST EFI_HANDLE       DriverBindingHandle,
524   IN CONST EFI_GUID         *ProtocolGuid
525   )
526 {
527   EFI_STATUS     Status;
528   VOID           *ManagedInterface;
529 
530   ASSERT (ProtocolGuid != NULL);
531 
532   Status = gBS->OpenProtocol (
533                   ControllerHandle,
534                   (EFI_GUID *) ProtocolGuid,
535                   &ManagedInterface,
536                   DriverBindingHandle,
537                   ControllerHandle,
538                   EFI_OPEN_PROTOCOL_BY_DRIVER
539                   );
540   if (!EFI_ERROR (Status)) {
541     gBS->CloseProtocol (
542            ControllerHandle,
543            (EFI_GUID *) ProtocolGuid,
544            DriverBindingHandle,
545            ControllerHandle
546            );
547     return EFI_UNSUPPORTED;
548   }
549 
550   if (Status != EFI_ALREADY_STARTED) {
551     return EFI_UNSUPPORTED;
552   }
553 
554   return EFI_SUCCESS;
555 }
556 
557 /**
558   Tests whether a child handle is a child device of the controller.
559 
560   This function tests whether ChildHandle is one of the children of
561   ControllerHandle.  This test is performed by checking to see if the protocol
562   specified by ProtocolGuid is present on ControllerHandle and opened by
563   ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
564   If ProtocolGuid is NULL, then ASSERT().
565 
566   @param  ControllerHandle     A handle for a (parent) controller to test.
567   @param  ChildHandle          A child handle to test.
568   @param  ProtocolGuid         Supplies the protocol that the child controller
569                                opens on its parent controller.
570 
571   @retval EFI_SUCCESS          ChildHandle is a child of the ControllerHandle.
572   @retval EFI_UNSUPPORTED      ChildHandle is not a child of the
573                                ControllerHandle.
574 
575 **/
576 EFI_STATUS
577 EFIAPI
EfiTestChildHandle(IN CONST EFI_HANDLE ControllerHandle,IN CONST EFI_HANDLE ChildHandle,IN CONST EFI_GUID * ProtocolGuid)578 EfiTestChildHandle (
579   IN CONST EFI_HANDLE       ControllerHandle,
580   IN CONST EFI_HANDLE       ChildHandle,
581   IN CONST EFI_GUID         *ProtocolGuid
582   )
583 {
584   EFI_STATUS                            Status;
585   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
586   UINTN                                 EntryCount;
587   UINTN                                 Index;
588 
589   ASSERT (ProtocolGuid != NULL);
590 
591   //
592   // Retrieve the list of agents that are consuming the specific protocol
593   // on ControllerHandle.
594   //
595   Status = gBS->OpenProtocolInformation (
596                   ControllerHandle,
597                   (EFI_GUID *) ProtocolGuid,
598                   &OpenInfoBuffer,
599                   &EntryCount
600                   );
601   if (EFI_ERROR (Status)) {
602     return EFI_UNSUPPORTED;
603   }
604 
605   //
606   // Inspect if ChildHandle is one of the agents.
607   //
608   Status = EFI_UNSUPPORTED;
609   for (Index = 0; Index < EntryCount; Index++) {
610     if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
611         (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
612       Status = EFI_SUCCESS;
613       break;
614     }
615   }
616 
617   FreePool (OpenInfoBuffer);
618   return Status;
619 }
620 
621 /**
622   This function looks up a Unicode string in UnicodeStringTable.
623 
624   If Language is a member of SupportedLanguages and a Unicode string is found in
625   UnicodeStringTable that matches the language code specified by Language, then it
626   is returned in UnicodeString.
627 
628   @param  Language                A pointer to the ISO 639-2 language code for the
629                                   Unicode string to look up and return.
630   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
631                                   that the Unicode string table supports.  Language
632                                   must be a member of this set.
633   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
634   @param  UnicodeString           A pointer to the Unicode string from UnicodeStringTable
635                                   that matches the language specified by Language.
636 
637   @retval EFI_SUCCESS             The Unicode string that matches the language
638                                   specified by Language was found
639                                   in the table of Unicode strings UnicodeStringTable,
640                                   and it was returned in UnicodeString.
641   @retval EFI_INVALID_PARAMETER   Language is NULL.
642   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
643   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
644   @retval EFI_UNSUPPORTED         UnicodeStringTable is NULL.
645   @retval EFI_UNSUPPORTED         The language specified by Language is not a
646                                   member of SupportedLanguages.
647   @retval EFI_UNSUPPORTED         The language specified by Language is not
648                                   supported by UnicodeStringTable.
649 
650 **/
651 EFI_STATUS
652 EFIAPI
LookupUnicodeString(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN CONST EFI_UNICODE_STRING_TABLE * UnicodeStringTable,OUT CHAR16 ** UnicodeString)653 LookupUnicodeString (
654   IN CONST CHAR8                     *Language,
655   IN CONST CHAR8                     *SupportedLanguages,
656   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
657   OUT CHAR16                         **UnicodeString
658   )
659 {
660   //
661   // Make sure the parameters are valid
662   //
663   if (Language == NULL || UnicodeString == NULL) {
664     return EFI_INVALID_PARAMETER;
665   }
666 
667   //
668   // If there are no supported languages, or the Unicode String Table is empty, then the
669   // Unicode String specified by Language is not supported by this Unicode String Table
670   //
671   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
672     return EFI_UNSUPPORTED;
673   }
674 
675   //
676   // Make sure Language is in the set of Supported Languages
677   //
678   while (*SupportedLanguages != 0) {
679     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
680 
681       //
682       // Search the Unicode String Table for the matching Language specifier
683       //
684       while (UnicodeStringTable->Language != NULL) {
685         if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
686 
687           //
688           // A matching string was found, so return it
689           //
690           *UnicodeString = UnicodeStringTable->UnicodeString;
691           return EFI_SUCCESS;
692         }
693 
694         UnicodeStringTable++;
695       }
696 
697       return EFI_UNSUPPORTED;
698     }
699 
700     SupportedLanguages += 3;
701   }
702 
703   return EFI_UNSUPPORTED;
704 }
705 
706 
707 
708 /**
709   This function looks up a Unicode string in UnicodeStringTable.
710 
711   If Language is a member of SupportedLanguages and a Unicode string is found in
712   UnicodeStringTable that matches the language code specified by Language, then
713   it is returned in UnicodeString.
714 
715   @param  Language             A pointer to an ASCII string containing the ISO 639-2 or the
716                                RFC 4646 language code for the Unicode string to look up and
717                                return. If Iso639Language is TRUE, then this ASCII string is
718                                not assumed to be Null-terminated, and only the first three
719                                characters are used. If Iso639Language is FALSE, then this ASCII
720                                string must be Null-terminated.
721   @param  SupportedLanguages   A pointer to a Null-terminated ASCII string that contains a
722                                set of ISO 639-2 or RFC 4646 language codes that the Unicode
723                                string table supports.  Language must be a member of this set.
724                                If Iso639Language is TRUE, then this string contains one or more
725                                ISO 639-2 language codes with no separator characters. If Iso639Language
726                                is FALSE, then is string contains one or more RFC 4646 language
727                                codes separated by ';'.
728   @param  UnicodeStringTable   A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
729                                is defined in "Related Definitions".
730   @param  UnicodeString        A pointer to the Null-terminated Unicode string from UnicodeStringTable
731                                that matches the language specified by Language.
732   @param  Iso639Language       Specifies the supported language code format. If it is TRUE, then
733                                Language and SupportedLanguages follow ISO 639-2 language code format.
734                                Otherwise, they follow RFC 4646 language code format.
735 
736 
737   @retval  EFI_SUCCESS            The Unicode string that matches the language specified by Language
738                                   was found in the table of Unicode strings UnicodeStringTable, and
739                                   it was returned in UnicodeString.
740   @retval  EFI_INVALID_PARAMETER  Language is NULL.
741   @retval  EFI_INVALID_PARAMETER  UnicodeString is NULL.
742   @retval  EFI_UNSUPPORTED        SupportedLanguages is NULL.
743   @retval  EFI_UNSUPPORTED        UnicodeStringTable is NULL.
744   @retval  EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
745   @retval  EFI_UNSUPPORTED        The language specified by Language is not supported by UnicodeStringTable.
746 
747 **/
748 EFI_STATUS
749 EFIAPI
LookupUnicodeString2(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN CONST EFI_UNICODE_STRING_TABLE * UnicodeStringTable,OUT CHAR16 ** UnicodeString,IN BOOLEAN Iso639Language)750 LookupUnicodeString2 (
751   IN CONST CHAR8                     *Language,
752   IN CONST CHAR8                     *SupportedLanguages,
753   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
754   OUT CHAR16                         **UnicodeString,
755   IN BOOLEAN                         Iso639Language
756   )
757 {
758   BOOLEAN   Found;
759   UINTN     Index;
760   CHAR8     *LanguageString;
761 
762   //
763   // Make sure the parameters are valid
764   //
765   if (Language == NULL || UnicodeString == NULL) {
766     return EFI_INVALID_PARAMETER;
767   }
768 
769   //
770   // If there are no supported languages, or the Unicode String Table is empty, then the
771   // Unicode String specified by Language is not supported by this Unicode String Table
772   //
773   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
774     return EFI_UNSUPPORTED;
775   }
776 
777   //
778   // Make sure Language is in the set of Supported Languages
779   //
780   Found = FALSE;
781   while (*SupportedLanguages != 0) {
782     if (Iso639Language) {
783       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
784         Found = TRUE;
785         break;
786       }
787       SupportedLanguages += 3;
788     } else {
789       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
790       if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
791         Found = TRUE;
792         break;
793       }
794       SupportedLanguages += Index;
795       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
796     }
797   }
798 
799   //
800   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
801   //
802   if (!Found) {
803     return EFI_UNSUPPORTED;
804   }
805 
806   //
807   // Search the Unicode String Table for the matching Language specifier
808   //
809   while (UnicodeStringTable->Language != NULL) {
810     LanguageString = UnicodeStringTable->Language;
811     while (0 != *LanguageString) {
812       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
813       if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {
814         *UnicodeString = UnicodeStringTable->UnicodeString;
815         return EFI_SUCCESS;
816       }
817       LanguageString += Index;
818       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);
819     }
820     UnicodeStringTable++;
821   }
822 
823   return EFI_UNSUPPORTED;
824 }
825 
826 
827 /**
828   This function adds a Unicode string to UnicodeStringTable.
829 
830   If Language is a member of SupportedLanguages then UnicodeString is added to
831   UnicodeStringTable.  New buffers are allocated for both Language and
832   UnicodeString.  The contents of Language and UnicodeString are copied into
833   these new buffers.  These buffers are automatically freed when
834   FreeUnicodeStringTable() is called.
835 
836   @param  Language                A pointer to the ISO 639-2 language code for the Unicode
837                                   string to add.
838   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
839                                   that the Unicode string table supports.
840                                   Language must be a member of this set.
841   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
842   @param  UnicodeString           A pointer to the Unicode string to add.
843 
844   @retval EFI_SUCCESS             The Unicode string that matches the language
845                                   specified by Language was found in the table of
846                                   Unicode strings UnicodeStringTable, and it was
847                                   returned in UnicodeString.
848   @retval EFI_INVALID_PARAMETER   Language is NULL.
849   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
850   @retval EFI_INVALID_PARAMETER   UnicodeString is an empty string.
851   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
852   @retval EFI_ALREADY_STARTED     A Unicode string with language Language is
853                                   already present in UnicodeStringTable.
854   @retval EFI_OUT_OF_RESOURCES    There is not enough memory to add another
855                                   Unicode string to UnicodeStringTable.
856   @retval EFI_UNSUPPORTED         The language specified by Language is not a
857                                   member of SupportedLanguages.
858 
859 **/
860 EFI_STATUS
861 EFIAPI
AddUnicodeString(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN OUT EFI_UNICODE_STRING_TABLE ** UnicodeStringTable,IN CONST CHAR16 * UnicodeString)862 AddUnicodeString (
863   IN     CONST CHAR8               *Language,
864   IN     CONST CHAR8               *SupportedLanguages,
865   IN OUT EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
866   IN     CONST CHAR16              *UnicodeString
867   )
868 {
869   UINTN                     NumberOfEntries;
870   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
871   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
872   UINTN                     UnicodeStringLength;
873 
874   //
875   // Make sure the parameter are valid
876   //
877   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
878     return EFI_INVALID_PARAMETER;
879   }
880 
881   //
882   // If there are no supported languages, then a Unicode String can not be added
883   //
884   if (SupportedLanguages == NULL) {
885     return EFI_UNSUPPORTED;
886   }
887 
888   //
889   // If the Unicode String is empty, then a Unicode String can not be added
890   //
891   if (UnicodeString[0] == 0) {
892     return EFI_INVALID_PARAMETER;
893   }
894 
895   //
896   // Make sure Language is a member of SupportedLanguages
897   //
898   while (*SupportedLanguages != 0) {
899     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
900 
901       //
902       // Determine the size of the Unicode String Table by looking for a NULL Language entry
903       //
904       NumberOfEntries = 0;
905       if (*UnicodeStringTable != NULL) {
906         OldUnicodeStringTable = *UnicodeStringTable;
907         while (OldUnicodeStringTable->Language != NULL) {
908           if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
909             return EFI_ALREADY_STARTED;
910           }
911 
912           OldUnicodeStringTable++;
913           NumberOfEntries++;
914         }
915       }
916 
917       //
918       // Allocate space for a new Unicode String Table.  It must hold the current number of
919       // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
920       // marker
921       //
922       NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
923       if (NewUnicodeStringTable == NULL) {
924         return EFI_OUT_OF_RESOURCES;
925       }
926 
927       //
928       // If the current Unicode String Table contains any entries, then copy them to the
929       // newly allocated Unicode String Table.
930       //
931       if (*UnicodeStringTable != NULL) {
932         CopyMem (
933            NewUnicodeStringTable,
934            *UnicodeStringTable,
935            NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
936            );
937       }
938 
939       //
940       // Allocate space for a copy of the Language specifier
941       //
942       NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
943       if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
944         gBS->FreePool (NewUnicodeStringTable);
945         return EFI_OUT_OF_RESOURCES;
946       }
947 
948       //
949       // Compute the length of the Unicode String
950       //
951       for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
952         ;
953 
954       //
955       // Allocate space for a copy of the Unicode String
956       //
957       NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
958                                                               (UnicodeStringLength + 1) * sizeof (CHAR16),
959                                                               UnicodeString
960                                                               );
961       if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
962         gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
963         gBS->FreePool (NewUnicodeStringTable);
964         return EFI_OUT_OF_RESOURCES;
965       }
966 
967       //
968       // Mark the end of the Unicode String Table
969       //
970       NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
971       NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
972 
973       //
974       // Free the old Unicode String Table
975       //
976       if (*UnicodeStringTable != NULL) {
977         gBS->FreePool (*UnicodeStringTable);
978       }
979 
980       //
981       // Point UnicodeStringTable at the newly allocated Unicode String Table
982       //
983       *UnicodeStringTable = NewUnicodeStringTable;
984 
985       return EFI_SUCCESS;
986     }
987 
988     SupportedLanguages += 3;
989   }
990 
991   return EFI_UNSUPPORTED;
992 }
993 
994 
995 /**
996   This function adds the Null-terminated Unicode string specified by UnicodeString
997   to UnicodeStringTable.
998 
999   If Language is a member of SupportedLanguages then UnicodeString is added to
1000   UnicodeStringTable.  New buffers are allocated for both Language and UnicodeString.
1001   The contents of Language and UnicodeString are copied into these new buffers.
1002   These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called.
1003 
1004   @param  Language            A pointer to an ASCII string containing the ISO 639-2 or
1005                               the RFC 4646 language code for the Unicode string to add.
1006                               If Iso639Language is TRUE, then this ASCII string is not
1007                               assumed to be Null-terminated, and only the first three
1008                               chacters are used. If Iso639Language is FALSE, then this
1009                               ASCII string must be Null-terminated.
1010   @param  SupportedLanguages  A pointer to a Null-terminated ASCII string that contains
1011                               a set of ISO 639-2 or RFC 4646 language codes that the Unicode
1012                               string table supports.  Language must be a member of this set.
1013                               If Iso639Language is TRUE, then this string contains one or more
1014                               ISO 639-2 language codes with no separator characters.
1015                               If Iso639Language is FALSE, then is string contains one or more
1016                               RFC 4646 language codes separated by ';'.
1017   @param  UnicodeStringTable  A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
1018                               is defined in "Related Definitions".
1019   @param  UnicodeString       A pointer to the Unicode string to add.
1020   @param  Iso639Language      Specifies the supported language code format. If it is TRUE,
1021                               then Language and SupportedLanguages follow ISO 639-2 language code format.
1022                               Otherwise, they follow RFC 4646 language code format.
1023 
1024   @retval EFI_SUCCESS            The Unicode string that matches the language specified by
1025                                  Language was found in the table of Unicode strings UnicodeStringTable,
1026                                  and it was returned in UnicodeString.
1027   @retval EFI_INVALID_PARAMETER  Language is NULL.
1028   @retval EFI_INVALID_PARAMETER  UnicodeString is NULL.
1029   @retval EFI_INVALID_PARAMETER  UnicodeString is an empty string.
1030   @retval EFI_UNSUPPORTED        SupportedLanguages is NULL.
1031   @retval EFI_ALREADY_STARTED    A Unicode string with language Language is already present in
1032                                  UnicodeStringTable.
1033   @retval EFI_OUT_OF_RESOURCES   There is not enough memory to add another Unicode string UnicodeStringTable.
1034   @retval EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
1035 
1036 **/
1037 EFI_STATUS
1038 EFIAPI
AddUnicodeString2(IN CONST CHAR8 * Language,IN CONST CHAR8 * SupportedLanguages,IN OUT EFI_UNICODE_STRING_TABLE ** UnicodeStringTable,IN CONST CHAR16 * UnicodeString,IN BOOLEAN Iso639Language)1039 AddUnicodeString2 (
1040   IN     CONST CHAR8               *Language,
1041   IN     CONST CHAR8               *SupportedLanguages,
1042   IN OUT EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
1043   IN     CONST CHAR16              *UnicodeString,
1044   IN     BOOLEAN                   Iso639Language
1045   )
1046 {
1047   UINTN                     NumberOfEntries;
1048   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
1049   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
1050   UINTN                     UnicodeStringLength;
1051   BOOLEAN                   Found;
1052   UINTN                     Index;
1053   CHAR8                     *LanguageString;
1054 
1055   //
1056   // Make sure the parameter are valid
1057   //
1058   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
1059     return EFI_INVALID_PARAMETER;
1060   }
1061 
1062   //
1063   // If there are no supported languages, then a Unicode String can not be added
1064   //
1065   if (SupportedLanguages == NULL) {
1066     return EFI_UNSUPPORTED;
1067   }
1068 
1069   //
1070   // If the Unicode String is empty, then a Unicode String can not be added
1071   //
1072   if (UnicodeString[0] == 0) {
1073     return EFI_INVALID_PARAMETER;
1074   }
1075 
1076   //
1077   // Make sure Language is a member of SupportedLanguages
1078   //
1079   Found = FALSE;
1080   while (*SupportedLanguages != 0) {
1081     if (Iso639Language) {
1082       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
1083         Found = TRUE;
1084         break;
1085       }
1086       SupportedLanguages += 3;
1087     } else {
1088       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
1089       if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {
1090         Found = TRUE;
1091         break;
1092       }
1093       SupportedLanguages += Index;
1094       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
1095     }
1096   }
1097 
1098   //
1099   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
1100   //
1101   if (!Found) {
1102     return EFI_UNSUPPORTED;
1103   }
1104 
1105   //
1106   // Determine the size of the Unicode String Table by looking for a NULL Language entry
1107   //
1108   NumberOfEntries = 0;
1109   if (*UnicodeStringTable != NULL) {
1110     OldUnicodeStringTable = *UnicodeStringTable;
1111     while (OldUnicodeStringTable->Language != NULL) {
1112       LanguageString = OldUnicodeStringTable->Language;
1113 
1114       while (*LanguageString != 0) {
1115         for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
1116 
1117         if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
1118           return EFI_ALREADY_STARTED;
1119         }
1120         LanguageString += Index;
1121         for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);
1122       }
1123       OldUnicodeStringTable++;
1124       NumberOfEntries++;
1125     }
1126   }
1127 
1128   //
1129   // Allocate space for a new Unicode String Table.  It must hold the current number of
1130   // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
1131   // marker
1132   //
1133   NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
1134   if (NewUnicodeStringTable == NULL) {
1135     return EFI_OUT_OF_RESOURCES;
1136   }
1137 
1138   //
1139   // If the current Unicode String Table contains any entries, then copy them to the
1140   // newly allocated Unicode String Table.
1141   //
1142   if (*UnicodeStringTable != NULL) {
1143     CopyMem (
1144       NewUnicodeStringTable,
1145       *UnicodeStringTable,
1146       NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
1147       );
1148   }
1149 
1150   //
1151   // Allocate space for a copy of the Language specifier
1152   //
1153   NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);
1154   if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
1155     gBS->FreePool (NewUnicodeStringTable);
1156     return EFI_OUT_OF_RESOURCES;
1157   }
1158 
1159   //
1160   // Compute the length of the Unicode String
1161   //
1162   for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);
1163 
1164   //
1165   // Allocate space for a copy of the Unicode String
1166   //
1167   NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
1168   if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
1169     gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
1170     gBS->FreePool (NewUnicodeStringTable);
1171     return EFI_OUT_OF_RESOURCES;
1172   }
1173 
1174   //
1175   // Mark the end of the Unicode String Table
1176   //
1177   NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
1178   NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
1179 
1180   //
1181   // Free the old Unicode String Table
1182   //
1183   if (*UnicodeStringTable != NULL) {
1184     gBS->FreePool (*UnicodeStringTable);
1185   }
1186 
1187   //
1188   // Point UnicodeStringTable at the newly allocated Unicode String Table
1189   //
1190   *UnicodeStringTable = NewUnicodeStringTable;
1191 
1192   return EFI_SUCCESS;
1193 }
1194 
1195 /**
1196   This function frees the table of Unicode strings in UnicodeStringTable.
1197 
1198   If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
1199   Otherwise, each language code, and each Unicode string in the Unicode string
1200   table are freed, and EFI_SUCCESS is returned.
1201 
1202   @param  UnicodeStringTable  A pointer to the table of Unicode strings.
1203 
1204   @retval EFI_SUCCESS         The Unicode string table was freed.
1205 
1206 **/
1207 EFI_STATUS
1208 EFIAPI
FreeUnicodeStringTable(IN EFI_UNICODE_STRING_TABLE * UnicodeStringTable)1209 FreeUnicodeStringTable (
1210   IN EFI_UNICODE_STRING_TABLE  *UnicodeStringTable
1211   )
1212 {
1213   UINTN Index;
1214 
1215   //
1216   // If the Unicode String Table is NULL, then it is already freed
1217   //
1218   if (UnicodeStringTable == NULL) {
1219     return EFI_SUCCESS;
1220   }
1221 
1222   //
1223   // Loop through the Unicode String Table until we reach the end of table marker
1224   //
1225   for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
1226 
1227     //
1228     // Free the Language string from the Unicode String Table
1229     //
1230     gBS->FreePool (UnicodeStringTable[Index].Language);
1231 
1232     //
1233     // Free the Unicode String from the Unicode String Table
1234     //
1235     if (UnicodeStringTable[Index].UnicodeString != NULL) {
1236       gBS->FreePool (UnicodeStringTable[Index].UnicodeString);
1237     }
1238   }
1239 
1240   //
1241   // Free the Unicode String Table itself
1242   //
1243   gBS->FreePool (UnicodeStringTable);
1244 
1245   return EFI_SUCCESS;
1246 }
1247 
1248 /**
1249   Returns a pointer to an allocated buffer that contains the contents of a
1250   variable retrieved through the UEFI Runtime Service GetVariable().  The
1251   returned buffer is allocated using AllocatePool().  The caller is responsible
1252   for freeing this buffer with FreePool().
1253 
1254   If Name is NULL, then ASSERT().
1255   If Guid is NULL, then ASSERT().
1256 
1257   @param[in]  Name  Pointer to a Null-terminated Unicode string.
1258   @param[in]  Guid  Pointer to an EFI_GUID structure
1259 
1260   @retval NULL   The variable could not be retrieved.
1261   @retval NULL   There are not enough resources available for the variable contents.
1262   @retval Other  A pointer to allocated buffer containing the variable contents.
1263 
1264 **/
1265 VOID *
1266 EFIAPI
GetVariable(IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid)1267 GetVariable (
1268   IN CONST CHAR16    *Name,
1269   IN CONST EFI_GUID  *Guid
1270   )
1271 {
1272   EFI_STATUS  Status;
1273   UINTN       Size;
1274   VOID        *Value;
1275 
1276   ASSERT (Name != NULL);
1277   ASSERT (Guid != NULL);
1278 
1279   //
1280   // Try to get the variable size.
1281   //
1282   Value = NULL;
1283   Size = 0;
1284   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
1285   if (Status != EFI_BUFFER_TOO_SMALL) {
1286     return NULL;
1287   }
1288 
1289   //
1290   // Allocate buffer to get the variable.
1291   //
1292   Value = AllocatePool (Size);
1293   if (Value == NULL) {
1294     return NULL;
1295   }
1296 
1297   //
1298   // Get the variable data.
1299   //
1300   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
1301   if (EFI_ERROR (Status)) {
1302     FreePool(Value);
1303     return NULL;
1304   }
1305 
1306   return Value;
1307 }
1308 
1309 
1310 /**
1311   Returns a pointer to an allocated buffer that contains the contents of a
1312   variable retrieved through the UEFI Runtime Service GetVariable().  This
1313   function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
1314   The returned buffer is allocated using AllocatePool().  The caller is
1315   responsible for freeing this buffer with FreePool().
1316 
1317   If Name is NULL, then ASSERT().
1318 
1319   @param[in]  Name  Pointer to a Null-terminated Unicode string.
1320 
1321   @retval NULL   The variable could not be retrieved.
1322   @retval NULL   There are not enough resources available for the variable contents.
1323   @retval Other  A pointer to allocated buffer containing the variable contents.
1324 
1325 **/
1326 VOID *
1327 EFIAPI
GetEfiGlobalVariable(IN CONST CHAR16 * Name)1328 GetEfiGlobalVariable (
1329   IN CONST CHAR16  *Name
1330   )
1331 {
1332   return GetVariable (Name, &gEfiGlobalVariableGuid);
1333 }
1334 
1335 /**
1336   Returns the status whether get the variable success. The function retrieves
1337   variable  through the UEFI Runtime Service GetVariable().  The
1338   returned buffer is allocated using AllocatePool().  The caller is responsible
1339   for freeing this buffer with FreePool().
1340 
1341   If Name  is NULL, then ASSERT().
1342   If Guid  is NULL, then ASSERT().
1343   If Value is NULL, then ASSERT().
1344 
1345   @param[in]  Name  The pointer to a Null-terminated Unicode string.
1346   @param[in]  Guid  The pointer to an EFI_GUID structure
1347   @param[out] Value The buffer point saved the variable info.
1348   @param[out] Size  The buffer size of the variable.
1349 
1350   @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
1351   @return EFI_SUCCESS               Find the specified variable.
1352   @return Others Errors             Return errors from call to gRT->GetVariable.
1353 
1354 **/
1355 EFI_STATUS
1356 EFIAPI
GetVariable2(IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid,OUT VOID ** Value,OUT UINTN * Size OPTIONAL)1357 GetVariable2 (
1358   IN CONST CHAR16    *Name,
1359   IN CONST EFI_GUID  *Guid,
1360   OUT VOID           **Value,
1361   OUT UINTN          *Size OPTIONAL
1362   )
1363 {
1364   EFI_STATUS  Status;
1365   UINTN       BufferSize;
1366 
1367   ASSERT (Name != NULL && Guid != NULL && Value != NULL);
1368 
1369   //
1370   // Try to get the variable size.
1371   //
1372   BufferSize = 0;
1373   *Value     = NULL;
1374   if (Size != NULL) {
1375     *Size  = 0;
1376   }
1377 
1378   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
1379   if (Status != EFI_BUFFER_TOO_SMALL) {
1380     return Status;
1381   }
1382 
1383   //
1384   // Allocate buffer to get the variable.
1385   //
1386   *Value = AllocatePool (BufferSize);
1387   ASSERT (*Value != NULL);
1388   if (*Value == NULL) {
1389     return EFI_OUT_OF_RESOURCES;
1390   }
1391 
1392   //
1393   // Get the variable data.
1394   //
1395   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
1396   if (EFI_ERROR (Status)) {
1397     FreePool(*Value);
1398     *Value = NULL;
1399   }
1400 
1401   if (Size != NULL) {
1402     *Size = BufferSize;
1403   }
1404 
1405   return Status;
1406 }
1407 
1408 /**
1409   Returns a pointer to an allocated buffer that contains the contents of a
1410   variable retrieved through the UEFI Runtime Service GetVariable().  This
1411   function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
1412   The returned buffer is allocated using AllocatePool().  The caller is
1413   responsible for freeing this buffer with FreePool().
1414 
1415   If Name is NULL, then ASSERT().
1416   If Value is NULL, then ASSERT().
1417 
1418   @param[in]  Name  The pointer to a Null-terminated Unicode string.
1419   @param[out] Value The buffer point saved the variable info.
1420   @param[out] Size  The buffer size of the variable.
1421 
1422   @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
1423   @return EFI_SUCCESS               Find the specified variable.
1424   @return Others Errors             Return errors from call to gRT->GetVariable.
1425 
1426 **/
1427 EFI_STATUS
1428 EFIAPI
GetEfiGlobalVariable2(IN CONST CHAR16 * Name,OUT VOID ** Value,OUT UINTN * Size OPTIONAL)1429 GetEfiGlobalVariable2 (
1430   IN CONST CHAR16    *Name,
1431   OUT VOID           **Value,
1432   OUT UINTN          *Size OPTIONAL
1433   )
1434 {
1435   return GetVariable2 (Name, &gEfiGlobalVariableGuid, Value, Size);
1436 }
1437 
1438 /**
1439   Returns a pointer to an allocated buffer that contains the best matching language
1440   from a set of supported languages.
1441 
1442   This function supports both ISO 639-2 and RFC 4646 language codes, but language
1443   code types may not be mixed in a single call to this function.  The language
1444   code returned is allocated using AllocatePool().  The caller is responsible for
1445   freeing the allocated buffer using FreePool().  This function supports a variable
1446   argument list that allows the caller to pass in a prioritized list of language
1447   codes to test against all the language codes in SupportedLanguages.
1448 
1449   If SupportedLanguages is NULL, then ASSERT().
1450 
1451   @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
1452                                   contains a set of language codes in the format
1453                                   specified by Iso639Language.
1454   @param[in]  Iso639Language      If not zero, then all language codes are assumed to be
1455                                   in ISO 639-2 format.  If zero, then all language
1456                                   codes are assumed to be in RFC 4646 language format
1457   @param[in]  ...                 A variable argument list that contains pointers to
1458                                   Null-terminated ASCII strings that contain one or more
1459                                   language codes in the format specified by Iso639Language.
1460                                   The first language code from each of these language
1461                                   code lists is used to determine if it is an exact or
1462                                   close match to any of the language codes in
1463                                   SupportedLanguages.  Close matches only apply to RFC 4646
1464                                   language codes, and the matching algorithm from RFC 4647
1465                                   is used to determine if a close match is present.  If
1466                                   an exact or close match is found, then the matching
1467                                   language code from SupportedLanguages is returned.  If
1468                                   no matches are found, then the next variable argument
1469                                   parameter is evaluated.  The variable argument list
1470                                   is terminated by a NULL.
1471 
1472   @retval NULL   The best matching language could not be found in SupportedLanguages.
1473   @retval NULL   There are not enough resources available to return the best matching
1474                  language.
1475   @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
1476                  language in SupportedLanguages.
1477 
1478 **/
1479 CHAR8 *
1480 EFIAPI
GetBestLanguage(IN CONST CHAR8 * SupportedLanguages,IN UINTN Iso639Language,...)1481 GetBestLanguage (
1482   IN CONST CHAR8  *SupportedLanguages,
1483   IN UINTN        Iso639Language,
1484   ...
1485   )
1486 {
1487   VA_LIST      Args;
1488   CHAR8        *Language;
1489   UINTN        CompareLength;
1490   UINTN        LanguageLength;
1491   CONST CHAR8  *Supported;
1492   CHAR8        *BestLanguage;
1493 
1494   ASSERT (SupportedLanguages != NULL);
1495 
1496   VA_START (Args, Iso639Language);
1497   while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1498     //
1499     // Default to ISO 639-2 mode
1500     //
1501     CompareLength  = 3;
1502     LanguageLength = MIN (3, AsciiStrLen (Language));
1503 
1504     //
1505     // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1506     //
1507     if (Iso639Language == 0) {
1508       for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
1509     }
1510 
1511     //
1512     // Trim back the length of Language used until it is empty
1513     //
1514     while (LanguageLength > 0) {
1515       //
1516       // Loop through all language codes in SupportedLanguages
1517       //
1518       for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1519         //
1520         // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1521         //
1522         if (Iso639Language == 0) {
1523           //
1524           // Skip ';' characters in Supported
1525           //
1526           for (; *Supported != '\0' && *Supported == ';'; Supported++);
1527           //
1528           // Determine the length of the next language code in Supported
1529           //
1530           for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
1531           //
1532           // If Language is longer than the Supported, then skip to the next language
1533           //
1534           if (LanguageLength > CompareLength) {
1535             continue;
1536           }
1537         }
1538         //
1539         // See if the first LanguageLength characters in Supported match Language
1540         //
1541         if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1542           VA_END (Args);
1543           //
1544           // Allocate, copy, and return the best matching language code from SupportedLanguages
1545           //
1546           BestLanguage = AllocateZeroPool (CompareLength + 1);
1547           if (BestLanguage == NULL) {
1548             return NULL;
1549           }
1550           return CopyMem (BestLanguage, Supported, CompareLength);
1551         }
1552       }
1553 
1554       if (Iso639Language != 0) {
1555         //
1556         // If ISO 639 mode, then each language can only be tested once
1557         //
1558         LanguageLength = 0;
1559       } else {
1560         //
1561         // If RFC 4646 mode, then trim Language from the right to the next '-' character
1562         //
1563         for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
1564       }
1565     }
1566   }
1567   VA_END (Args);
1568 
1569   //
1570   // No matches were found
1571   //
1572   return NULL;
1573 }
1574 
1575 /**
1576   Returns an array of protocol instance that matches the given protocol.
1577 
1578   @param[in]  Protocol      Provides the protocol to search for.
1579   @param[out] NoProtocols   The number of protocols returned in Buffer.
1580   @param[out] Buffer        A pointer to the buffer to return the requested
1581                             array of protocol instances that match Protocol.
1582                             The returned buffer is allocated using
1583                             EFI_BOOT_SERVICES.AllocatePool().  The caller is
1584                             responsible for freeing this buffer with
1585                             EFI_BOOT_SERVICES.FreePool().
1586 
1587   @retval EFI_SUCCESS            The array of protocols was returned in Buffer,
1588                                  and the number of protocols in Buffer was
1589                                  returned in NoProtocols.
1590   @retval EFI_NOT_FOUND          No protocols found.
1591   @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the
1592                                  matching results.
1593   @retval EFI_INVALID_PARAMETER  Protocol is NULL.
1594   @retval EFI_INVALID_PARAMETER  NoProtocols is NULL.
1595   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
1596 
1597 **/
1598 EFI_STATUS
1599 EFIAPI
EfiLocateProtocolBuffer(IN EFI_GUID * Protocol,OUT UINTN * NoProtocols,OUT VOID *** Buffer)1600 EfiLocateProtocolBuffer (
1601   IN  EFI_GUID  *Protocol,
1602   OUT UINTN     *NoProtocols,
1603   OUT VOID      ***Buffer
1604   )
1605 {
1606   EFI_STATUS  Status;
1607   UINTN       NoHandles;
1608   EFI_HANDLE  *HandleBuffer;
1609   UINTN       Index;
1610 
1611   //
1612   // Check input parameters
1613   //
1614   if (Protocol == NULL || NoProtocols == NULL || Buffer == NULL) {
1615     return EFI_INVALID_PARAMETER;
1616   }
1617 
1618   //
1619   // Initialze output parameters
1620   //
1621   *NoProtocols = 0;
1622   *Buffer = NULL;
1623 
1624   //
1625   // Retrieve the array of handles that support Protocol
1626   //
1627   Status = gBS->LocateHandleBuffer (
1628                   ByProtocol,
1629                   Protocol,
1630                   NULL,
1631                   &NoHandles,
1632                   &HandleBuffer
1633                   );
1634   if (EFI_ERROR (Status)) {
1635     return Status;
1636   }
1637 
1638   //
1639   // Allocate array of protocol instances
1640   //
1641   Status = gBS->AllocatePool (
1642                   EfiBootServicesData,
1643                   NoHandles * sizeof (VOID *),
1644                   (VOID **)Buffer
1645                   );
1646   if (EFI_ERROR (Status)) {
1647     //
1648     // Free the handle buffer
1649     //
1650     gBS->FreePool (HandleBuffer);
1651     return EFI_OUT_OF_RESOURCES;
1652   }
1653   ZeroMem (*Buffer, NoHandles * sizeof (VOID *));
1654 
1655   //
1656   // Lookup Protocol on each handle in HandleBuffer to fill in the array of
1657   // protocol instances.  Handle case where protocol instance was present when
1658   // LocateHandleBuffer() was called, but is not present when HandleProtocol()
1659   // is called.
1660   //
1661   for (Index = 0, *NoProtocols = 0; Index < NoHandles; Index++) {
1662     Status = gBS->HandleProtocol (
1663                     HandleBuffer[Index],
1664                     Protocol,
1665                     &((*Buffer)[*NoProtocols])
1666                     );
1667     if (!EFI_ERROR (Status)) {
1668       (*NoProtocols)++;
1669     }
1670   }
1671 
1672   //
1673   // Free the handle buffer
1674   //
1675   gBS->FreePool (HandleBuffer);
1676 
1677   //
1678   // Make sure at least one protocol instance was found
1679   //
1680   if (*NoProtocols == 0) {
1681     gBS->FreePool (*Buffer);
1682     *Buffer = NULL;
1683     return EFI_NOT_FOUND;
1684   }
1685 
1686   return EFI_SUCCESS;
1687 }
1688 
1689 /**
1690   Open or create a file or directory, possibly creating the chain of
1691   directories leading up to the directory.
1692 
1693   EfiOpenFileByDevicePath() first locates EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on
1694   FilePath, and opens the root directory of that filesystem with
1695   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume().
1696 
1697   On the remaining device path, the longest initial sequence of
1698   FILEPATH_DEVICE_PATH nodes is node-wise traversed with
1699   EFI_FILE_PROTOCOL.Open().
1700 
1701   (As a consequence, if OpenMode includes EFI_FILE_MODE_CREATE, and Attributes
1702   includes EFI_FILE_DIRECTORY, and each FILEPATH_DEVICE_PATH specifies a single
1703   pathname component, then EfiOpenFileByDevicePath() ensures that the specified
1704   series of subdirectories exist on return.)
1705 
1706   The EFI_FILE_PROTOCOL identified by the last FILEPATH_DEVICE_PATH node is
1707   output to the caller; intermediate EFI_FILE_PROTOCOL instances are closed. If
1708   there are no FILEPATH_DEVICE_PATH nodes past the node that identifies the
1709   filesystem, then the EFI_FILE_PROTOCOL of the root directory of the
1710   filesystem is output to the caller. If a device path node that is different
1711   from FILEPATH_DEVICE_PATH is encountered relative to the filesystem, the
1712   traversal is stopped with an error, and a NULL EFI_FILE_PROTOCOL is output.
1713 
1714   @param[in,out] FilePath  On input, the device path to the file or directory
1715                            to open or create. The caller is responsible for
1716                            ensuring that the device path pointed-to by FilePath
1717                            is well-formed. On output, FilePath points one past
1718                            the last node in the original device path that has
1719                            been successfully processed. FilePath is set on
1720                            output even if EfiOpenFileByDevicePath() returns an
1721                            error.
1722 
1723   @param[out] File         On error, File is set to NULL. On success, File is
1724                            set to the EFI_FILE_PROTOCOL of the root directory
1725                            of the filesystem, if there are no
1726                            FILEPATH_DEVICE_PATH nodes in FilePath; otherwise,
1727                            File is set to the EFI_FILE_PROTOCOL identified by
1728                            the last node in FilePath.
1729 
1730   @param[in] OpenMode      The OpenMode parameter to pass to
1731                            EFI_FILE_PROTOCOL.Open().
1732 
1733   @param[in] Attributes    The Attributes parameter to pass to
1734                            EFI_FILE_PROTOCOL.Open().
1735 
1736   @retval EFI_SUCCESS            The file or directory has been opened or
1737                                  created.
1738 
1739   @retval EFI_INVALID_PARAMETER  FilePath is NULL; or File is NULL; or FilePath
1740                                  contains a device path node, past the node
1741                                  that identifies
1742                                  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, that is not a
1743                                  FILEPATH_DEVICE_PATH node.
1744 
1745   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
1746 
1747   @return                        Error codes propagated from the
1748                                  LocateDevicePath() and OpenProtocol() boot
1749                                  services, and from the
1750                                  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume()
1751                                  and EFI_FILE_PROTOCOL.Open() member functions.
1752 **/
1753 EFI_STATUS
1754 EFIAPI
EfiOpenFileByDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL ** FilePath,OUT EFI_FILE_PROTOCOL ** File,IN UINT64 OpenMode,IN UINT64 Attributes)1755 EfiOpenFileByDevicePath (
1756   IN OUT EFI_DEVICE_PATH_PROTOCOL  **FilePath,
1757   OUT    EFI_FILE_PROTOCOL         **File,
1758   IN     UINT64                    OpenMode,
1759   IN     UINT64                    Attributes
1760   )
1761 {
1762   EFI_STATUS                      Status;
1763   EFI_HANDLE                      FileSystemHandle;
1764   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
1765   EFI_FILE_PROTOCOL               *LastFile;
1766   FILEPATH_DEVICE_PATH            *FilePathNode;
1767   CHAR16                          *AlignedPathName;
1768   CHAR16                          *PathName;
1769   EFI_FILE_PROTOCOL               *NextFile;
1770 
1771   if (File == NULL) {
1772     return EFI_INVALID_PARAMETER;
1773   }
1774   *File = NULL;
1775 
1776   if (FilePath == NULL) {
1777     return EFI_INVALID_PARAMETER;
1778   }
1779 
1780   //
1781   // Look up the filesystem.
1782   //
1783   Status = gBS->LocateDevicePath (
1784                   &gEfiSimpleFileSystemProtocolGuid,
1785                   FilePath,
1786                   &FileSystemHandle
1787                   );
1788   if (EFI_ERROR (Status)) {
1789     return Status;
1790   }
1791   Status = gBS->OpenProtocol (
1792                   FileSystemHandle,
1793                   &gEfiSimpleFileSystemProtocolGuid,
1794                   (VOID **)&FileSystem,
1795                   gImageHandle,
1796                   NULL,
1797                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
1798                   );
1799   if (EFI_ERROR (Status)) {
1800     return Status;
1801   }
1802 
1803   //
1804   // Open the root directory of the filesystem. After this operation succeeds,
1805   // we have to release LastFile on error.
1806   //
1807   Status = FileSystem->OpenVolume (FileSystem, &LastFile);
1808   if (EFI_ERROR (Status)) {
1809     return Status;
1810   }
1811 
1812   //
1813   // Traverse the device path nodes relative to the filesystem.
1814   //
1815   while (!IsDevicePathEnd (*FilePath)) {
1816     if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
1817         DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP) {
1818       Status = EFI_INVALID_PARAMETER;
1819       goto CloseLastFile;
1820     }
1821     FilePathNode = (FILEPATH_DEVICE_PATH *)*FilePath;
1822 
1823     //
1824     // FilePathNode->PathName may be unaligned, and the UEFI specification
1825     // requires pointers that are passed to protocol member functions to be
1826     // aligned. Create an aligned copy of the pathname if necessary.
1827     //
1828     if ((UINTN)FilePathNode->PathName % sizeof *FilePathNode->PathName == 0) {
1829       AlignedPathName = NULL;
1830       PathName = FilePathNode->PathName;
1831     } else {
1832       AlignedPathName = AllocateCopyPool (
1833                           (DevicePathNodeLength (FilePathNode) -
1834                            SIZE_OF_FILEPATH_DEVICE_PATH),
1835                           FilePathNode->PathName
1836                           );
1837       if (AlignedPathName == NULL) {
1838         Status = EFI_OUT_OF_RESOURCES;
1839         goto CloseLastFile;
1840       }
1841       PathName = AlignedPathName;
1842     }
1843 
1844     //
1845     // Open or create the file corresponding to the next pathname fragment.
1846     //
1847     Status = LastFile->Open (
1848                          LastFile,
1849                          &NextFile,
1850                          PathName,
1851                          OpenMode,
1852                          Attributes
1853                          );
1854 
1855     //
1856     // Release any AlignedPathName on both error and success paths; PathName is
1857     // no longer needed.
1858     //
1859     if (AlignedPathName != NULL) {
1860       FreePool (AlignedPathName);
1861     }
1862     if (EFI_ERROR (Status)) {
1863       goto CloseLastFile;
1864     }
1865 
1866     //
1867     // Advance to the next device path node.
1868     //
1869     LastFile->Close (LastFile);
1870     LastFile = NextFile;
1871     *FilePath = NextDevicePathNode (FilePathNode);
1872   }
1873 
1874   *File = LastFile;
1875   return EFI_SUCCESS;
1876 
1877 CloseLastFile:
1878   LastFile->Close (LastFile);
1879 
1880   //
1881   // We are on the error path; we must have set an error Status for returning
1882   // to the caller.
1883   //
1884   ASSERT (EFI_ERROR (Status));
1885   return Status;
1886 }
1887