]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiLib/UefiLib.c
Code and comments have been checked with spec.
[mirror_edk2.git] / MdePkg / Library / UefiLib / UefiLib.c
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 - 2007, Intel Corporation<BR>
9 All rights reserved. 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
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
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.
96 In addition, every time a protocol of type ProtocolGuid instance is installed or reinstalled,
97 the notification function is also executed. This function returns the notification event
98 that was created.
99 If ProtocolGuid is NULL, then ASSERT().
100 If NotifyTpl is not a legal TPL value, then ASSERT().
101 If NotifyFunction is NULL, then ASSERT().
102 If Registration is NULL, then ASSERT().
103
104 @param ProtocolGuid Supplies GUID of the protocol upon whose installation the event is fired.
105 @param NotifyTpl Supplies the task priority level of the event notifications.
106 @param NotifyFunction Supplies the function to notify when the event is signaled.
107 @param NotifyContext The context parameter to pass to NotifyFunction.
108 @param Registration A pointer to a memory location to receive the registration value.
109 This value is passed to LocateHandle() to obtain new handles that
110 have been added that support the ProtocolGuid-specified protocol.
111
112 @return The notification event that was created.
113
114 **/
115 EFI_EVENT
116 EFIAPI
117 EfiCreateProtocolNotifyEvent(
118 IN EFI_GUID *ProtocolGuid,
119 IN EFI_TPL NotifyTpl,
120 IN EFI_EVENT_NOTIFY NotifyFunction,
121 IN VOID *NotifyContext, OPTIONAL
122 OUT VOID **Registration
123 )
124 {
125 EFI_STATUS Status;
126 EFI_EVENT Event;
127
128 ASSERT (ProtocolGuid != NULL);
129 ASSERT (NotifyFunction != NULL);
130 ASSERT (Registration != NULL);
131
132 //
133 // Create the event
134 //
135
136 Status = gBS->CreateEvent (
137 EVT_NOTIFY_SIGNAL,
138 NotifyTpl,
139 NotifyFunction,
140 NotifyContext,
141 &Event
142 );
143 ASSERT_EFI_ERROR (Status);
144
145 //
146 // Register for protocol notifactions on this event
147 //
148
149 Status = gBS->RegisterProtocolNotify (
150 ProtocolGuid,
151 Event,
152 Registration
153 );
154
155 ASSERT_EFI_ERROR (Status);
156
157 //
158 // Kick the event so we will perform an initial pass of
159 // current installed drivers
160 //
161
162 gBS->SignalEvent (Event);
163 return Event;
164 }
165
166 /**
167 Creates a named event that can be signaled with EfiNamedEventSignal().
168
169 This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.
170 This event is signaled with EfiNamedEventSignal(). This provides the ability for one or more
171 listeners on the same event named by the GUID specified by Name.
172 If Name is NULL, then ASSERT().
173 If NotifyTpl is not a legal TPL value, then ASSERT().
174 If NotifyFunction is NULL, then ASSERT().
175
176 @param Name Supplies GUID name of the event.
177 @param NotifyTpl Supplies the task priority level of the event notifications.
178 @param NotifyFunction Supplies the function to notify when the event is signaled.
179 @param NotifyContext The context parameter to pass to NotifyFunction.
180 @param Registration A pointer to a memory location to receive the registration value.
181
182 @retval EFI_SUCCESS A named event was created.
183 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
184
185 **/
186 EFI_STATUS
187 EFIAPI
188 EfiNamedEventListen (
189 IN CONST EFI_GUID *Name,
190 IN EFI_TPL NotifyTpl,
191 IN EFI_EVENT_NOTIFY NotifyFunction,
192 IN CONST VOID *NotifyContext, OPTIONAL
193 OUT VOID *Registration OPTIONAL
194 )
195 {
196 EFI_STATUS Status;
197 EFI_EVENT Event;
198 VOID *RegistrationLocal;
199
200 ASSERT (Name != NULL);
201 ASSERT (NotifyFunction != NULL);
202 ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
203
204 //
205 // Create event
206 //
207 Status = gBS->CreateEvent (
208 EVT_NOTIFY_SIGNAL,
209 NotifyTpl,
210 NotifyFunction,
211 (VOID *) NotifyContext,
212 &Event
213 );
214 ASSERT_EFI_ERROR (Status);
215
216 //
217 // The Registration is not optional to RegisterProtocolNotify().
218 // To make it optional to EfiNamedEventListen(), may need to substitute with a local.
219 //
220 if (Registration != NULL) {
221 RegistrationLocal = Registration;
222 } else {
223 RegistrationLocal = &RegistrationLocal;
224 }
225
226 //
227 // Register for an installation of protocol interface
228 //
229
230 Status = gBS->RegisterProtocolNotify (
231 (EFI_GUID *) Name,
232 Event,
233 RegistrationLocal
234 );
235 ASSERT_EFI_ERROR (Status);
236
237 return Status;
238 }
239
240 /**
241 Signals a named event created with EfiNamedEventListen().
242
243 This function signals the named event specified by Name. The named event must have been
244 created with EfiNamedEventListen().
245 If Name is NULL, then ASSERT().
246
247 @param Name Supplies GUID name of the event.
248
249 @retval EFI_SUCCESS A named event was signaled.
250 @retval EFI_OUT_OF_RESOURCES There are not enough resource to signal the named event.
251
252 **/
253 EFI_STATUS
254 EFIAPI
255 EfiNamedEventSignal (
256 IN CONST EFI_GUID *Name
257 )
258 {
259 EFI_STATUS Status;
260 EFI_HANDLE Handle;
261
262 ASSERT(Name != NULL);
263
264 Handle = NULL;
265 Status = gBS->InstallProtocolInterface (
266 &Handle,
267 (EFI_GUID *) Name,
268 EFI_NATIVE_INTERFACE,
269 NULL
270 );
271 ASSERT_EFI_ERROR (Status);
272
273 Status = gBS->UninstallProtocolInterface (
274 Handle,
275 (EFI_GUID *) Name,
276 NULL
277 );
278 ASSERT_EFI_ERROR (Status);
279
280 return Status;
281 }
282
283 /**
284 Returns the current TPL.
285
286 This function returns the current TPL. There is no EFI service to directly
287 retrieve the current TPL. Instead, the RaiseTPL() function is used to raise
288 the TPL to TPL_HIGH_LEVEL. This will return the current TPL. The TPL level
289 can then immediately be restored back to the current TPL level with a call
290 to RestoreTPL().
291
292 @param VOID
293
294 @retval EFI_TPL The current TPL.
295
296 **/
297 EFI_TPL
298 EFIAPI
299 EfiGetCurrentTpl (
300 VOID
301 )
302 {
303 EFI_TPL Tpl;
304
305 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
306 gBS->RestoreTPL (Tpl);
307
308 return Tpl;
309 }
310
311
312 /**
313 Initializes a basic mutual exclusion lock.
314
315 This function initializes a basic mutual exclusion lock to the released state
316 and returns the lock. Each lock provides mutual exclusion access at its task
317 priority level. Since there is no preemption or multiprocessor support in EFI,
318 acquiring the lock only consists of raising to the locks TPL.
319 If Lock is NULL, then ASSERT().
320 If Priority is not a valid TPL value, then ASSERT().
321
322 @param Lock A pointer to the lock data structure to initialize.
323 @param Priority EFI TPL associated with the lock.
324
325 @return The lock.
326
327 **/
328 EFI_LOCK *
329 EFIAPI
330 EfiInitializeLock (
331 IN OUT EFI_LOCK *Lock,
332 IN EFI_TPL Priority
333 )
334 {
335 ASSERT (Lock != NULL);
336 ASSERT (Priority <= TPL_HIGH_LEVEL);
337
338 Lock->Tpl = Priority;
339 Lock->OwnerTpl = TPL_APPLICATION;
340 Lock->Lock = EfiLockReleased ;
341 return Lock;
342 }
343
344 /**
345 Acquires ownership of a lock.
346
347 This function raises the system's current task priority level to the task
348 priority level of the mutual exclusion lock. Then, it places the lock in the
349 acquired state.
350 If Lock is NULL, then ASSERT().
351 If Lock is not initialized, then ASSERT().
352 If Lock is already in the acquired state, then ASSERT().
353
354 @param Lock A pointer to the lock to acquire.
355
356 **/
357 VOID
358 EFIAPI
359 EfiAcquireLock (
360 IN EFI_LOCK *Lock
361 )
362 {
363 ASSERT (Lock != NULL);
364 ASSERT (Lock->Lock == EfiLockReleased);
365
366 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
367 Lock->Lock = EfiLockAcquired;
368 }
369
370 /**
371 Acquires ownership of a lock. If the lock is already owned , then an error is returned.
372
373 This function raises the system's current task priority level to the task
374 priority level of the mutual exclusion lock. Then, it attempts to place the
375 lock in the acquired state.
376 If Lock is NULL, then ASSERT().
377 If Lock is not initialized, then ASSERT().
378
379 @param Lock A pointer to the lock to acquire.
380
381 @retval EFI_SUCCESS The lock was acquired.
382 @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
383
384 **/
385 EFI_STATUS
386 EFIAPI
387 EfiAcquireLockOrFail (
388 IN EFI_LOCK *Lock
389 )
390 {
391
392 ASSERT (Lock != NULL);
393 ASSERT (Lock->Lock != EfiLockUninitialized);
394
395 if (Lock->Lock == EfiLockAcquired) {
396 //
397 // Lock is already owned, so bail out
398 //
399 return EFI_ACCESS_DENIED;
400 }
401
402 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
403
404 Lock->Lock = EfiLockAcquired;
405
406 return EFI_SUCCESS;
407 }
408
409 /**
410 Releases ownership of a lock.
411
412 This function transitions a mutual exclusion lock from the acquired state to
413 the released state, and restores the system's task priority level to its
414 previous level.
415 If Lock is NULL, then ASSERT().
416 If Lock is not initialized, then ASSERT().
417 If Lock is already in the released state, then ASSERT().
418
419 @param Lock A pointer to the lock to release.
420
421 **/
422 VOID
423 EFIAPI
424 EfiReleaseLock (
425 IN EFI_LOCK *Lock
426 )
427 {
428 EFI_TPL Tpl;
429
430 ASSERT (Lock != NULL);
431 ASSERT (Lock->Lock == EfiLockAcquired);
432
433 Tpl = Lock->OwnerTpl;
434
435 Lock->Lock = EfiLockReleased;
436
437 gBS->RestoreTPL (Tpl);
438 }
439
440 /**
441 Tests whether a controller handle is being managed by a specific driver.
442
443 This function tests whether the driver specified by DriverBindingHandle is
444 currently managing the controller specified by ControllerHandle. This test
445 is performed by evaluating if the the protocol specified by ProtocolGuid is
446 present on ControllerHandle and is was opened by DriverBindingHandle with an
447 attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
448 If ProtocolGuid is NULL, then ASSERT().
449
450 @param ControllerHandle A handle for a controller to test.
451 @param DriverBindingHandle Specifies the driver binding handle for the
452 driver.
453 @param ProtocolGuid Specifies the protocol that the driver specified
454 by DriverBindingHandle opens in its Start()
455 function.
456
457 @retval EFI_SUCCESS ControllerHandle is managed by the driver
458 specifed by DriverBindingHandle.
459 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
460 specifed by DriverBindingHandle.
461
462 **/
463 EFI_STATUS
464 EFIAPI
465 EfiTestManagedDevice (
466 IN CONST EFI_HANDLE ControllerHandle,
467 IN CONST EFI_HANDLE DriverBindingHandle,
468 IN CONST EFI_GUID *ProtocolGuid
469 )
470 {
471 EFI_STATUS Status;
472 VOID *ManagedInterface;
473
474 ASSERT (ProtocolGuid != NULL);
475
476 Status = gBS->OpenProtocol (
477 ControllerHandle,
478 (EFI_GUID *) ProtocolGuid,
479 &ManagedInterface,
480 DriverBindingHandle,
481 ControllerHandle,
482 EFI_OPEN_PROTOCOL_BY_DRIVER
483 );
484 if (!EFI_ERROR (Status)) {
485 gBS->CloseProtocol (
486 ControllerHandle,
487 (EFI_GUID *) ProtocolGuid,
488 DriverBindingHandle,
489 ControllerHandle
490 );
491 return EFI_UNSUPPORTED;
492 }
493
494 if (Status != EFI_ALREADY_STARTED) {
495 return EFI_UNSUPPORTED;
496 }
497
498 return EFI_SUCCESS;
499 }
500
501 /**
502 Tests whether a child handle is a child device of the controller.
503
504 This function tests whether ChildHandle is one of the children of
505 ControllerHandle. This test is performed by checking to see if the protocol
506 specified by ProtocolGuid is present on ControllerHandle and opened by
507 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
508 If ProtocolGuid is NULL, then ASSERT().
509
510 @param ControllerHandle A handle for a (parent) controller to test.
511 @param ChildHandle A child handle to test.
512 @param ProtocolGuid Supplies the protocol that the child controller
513 opens on its parent controller.
514
515 @retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle.
516 @retval EFI_UNSUPPORTED ChildHandle is not a child of the
517 ControllerHandle.
518
519 **/
520 EFI_STATUS
521 EFIAPI
522 EfiTestChildHandle (
523 IN CONST EFI_HANDLE ControllerHandle,
524 IN CONST EFI_HANDLE ChildHandle,
525 IN CONST EFI_GUID *ProtocolGuid
526 )
527 {
528 EFI_STATUS Status;
529 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
530 UINTN EntryCount;
531 UINTN Index;
532
533 ASSERT (ProtocolGuid != NULL);
534
535 //
536 // Retrieve the list of agents that are consuming the specific protocol
537 // on ControllerHandle.
538 //
539 Status = gBS->OpenProtocolInformation (
540 ControllerHandle,
541 (EFI_GUID *) ProtocolGuid,
542 &OpenInfoBuffer,
543 &EntryCount
544 );
545 if (EFI_ERROR (Status)) {
546 return EFI_UNSUPPORTED;
547 }
548
549 //
550 // Inspect if ChildHandle is one of the agents.
551 //
552 Status = EFI_UNSUPPORTED;
553 for (Index = 0; Index < EntryCount; Index++) {
554 if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
555 (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
556 Status = EFI_SUCCESS;
557 break;
558 }
559 }
560
561 FreePool (OpenInfoBuffer);
562 return Status;
563 }
564
565 /**
566 This function looks up a Unicode string in UnicodeStringTable.
567
568 If Language is a member of SupportedLanguages and a Unicode string is found in
569 UnicodeStringTable that matches the language code specified by Language, then it
570 is returned in UnicodeString.
571
572 @param Language A pointer to the ISO 639-2 language code for the
573 Unicode string to look up and return.
574 @param SupportedLanguages A pointer to the set of ISO 639-2 language codes
575 that the Unicode string table supports. Language
576 must be a member of this set.
577 @param UnicodeStringTable A pointer to the table of Unicode strings.
578 @param UnicodeString A pointer to the Unicode string from UnicodeStringTable
579 that matches the language specified by Language.
580
581 @retval EFI_SUCCESS The Unicode string that matches the language
582 specified by Language was found
583 in the table of Unicoide strings UnicodeStringTable,
584 and it was returned in UnicodeString.
585 @retval EFI_INVALID_PARAMETER Language is NULL.
586 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
587 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
588 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.
589 @retval EFI_UNSUPPORTED The language specified by Language is not a
590 member of SupportedLanguages.
591 @retval EFI_UNSUPPORTED The language specified by Language is not
592 supported by UnicodeStringTable.
593
594 **/
595 EFI_STATUS
596 EFIAPI
597 LookupUnicodeString (
598 IN CONST CHAR8 *Language,
599 IN CONST CHAR8 *SupportedLanguages,
600 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,
601 OUT CHAR16 **UnicodeString
602 )
603 {
604 //
605 // Make sure the parameters are valid
606 //
607 if (Language == NULL || UnicodeString == NULL) {
608 return EFI_INVALID_PARAMETER;
609 }
610
611 //
612 // If there are no supported languages, or the Unicode String Table is empty, then the
613 // Unicode String specified by Language is not supported by this Unicode String Table
614 //
615 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
616 return EFI_UNSUPPORTED;
617 }
618
619 //
620 // Make sure Language is in the set of Supported Languages
621 //
622 while (*SupportedLanguages != 0) {
623 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
624
625 //
626 // Search the Unicode String Table for the matching Language specifier
627 //
628 while (UnicodeStringTable->Language != NULL) {
629 if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
630
631 //
632 // A matching string was found, so return it
633 //
634 *UnicodeString = UnicodeStringTable->UnicodeString;
635 return EFI_SUCCESS;
636 }
637
638 UnicodeStringTable++;
639 }
640
641 return EFI_UNSUPPORTED;
642 }
643
644 SupportedLanguages += 3;
645 }
646
647 return EFI_UNSUPPORTED;
648 }
649
650
651
652 /**
653 This function looks up a Unicode string in UnicodeStringTable.
654 If Language is a member of SupportedLanguages and a Unicode
655 string is found in UnicodeStringTable that matches the
656 language code specified by Language, then it is returned in
657 UnicodeString.
658
659 @param Language A pointer to the ISO 639-2 or
660 RFC 3066 language code for the
661 Unicode string to look up and
662 return.
663 @param SupportedLanguages A pointer to the set of ISO
664 639-2 or RFC 3066 language
665 codes that the Unicode string
666 table supports. Language must
667 be a member of this set.
668 @param UnicodeStringTable A pointer to the table of
669 Unicode strings.
670 @param UnicodeString A pointer to the Unicode
671 string from UnicodeStringTable
672 that matches the language
673 specified by Language.
674 @param Iso639Language Specify the language code
675 format supported. If true,
676 then the format follow ISO
677 639-2. If false, then it
678 follows RFC3066.
679 @retval EFI_SUCCESS The Unicode string that
680 matches the language specified
681 by Language was found in the
682 table of Unicoide strings
683 UnicodeStringTable, and it was
684 returned in UnicodeString.
685
686 @retval EFI_INVALID_PARAMETER Language is NULL.
687 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
688 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
689 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.
690 @retval EFI_UNSUPPORTED The language specified by
691 Language is not a member
692 ofSupportedLanguages.
693 @retval EFI_UNSUPPORTED The language specified by
694 Language is not supported by
695 UnicodeStringTable.
696
697 **/
698 EFI_STATUS
699
700 EFIAPI
701 LookupUnicodeString2 (
702 IN CONST CHAR8 *Language,
703 IN CONST CHAR8 *SupportedLanguages,
704 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,
705 OUT CHAR16 **UnicodeString,
706 IN BOOLEAN Iso639Language
707 )
708 {
709 BOOLEAN Found;
710 UINTN Index;
711 CHAR8 *LanguageString;
712
713 //
714 // Make sure the parameters are valid
715 //
716 if (Language == NULL || UnicodeString == NULL) {
717 return EFI_INVALID_PARAMETER;
718 }
719
720 //
721 // If there are no supported languages, or the Unicode String Table is empty, then the
722 // Unicode String specified by Language is not supported by this Unicode String Table
723 //
724 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
725 return EFI_UNSUPPORTED;
726 }
727
728 //
729 // Make sure Language is in the set of Supported Languages
730 //
731 Found = FALSE;
732 while (*SupportedLanguages != 0) {
733 if (Iso639Language) {
734 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
735 Found = TRUE;
736 break;
737 }
738 SupportedLanguages += 3;
739 } else {
740 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
741 if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
742 Found = TRUE;
743 break;
744 }
745 SupportedLanguages += Index;
746 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
747 }
748 }
749
750 //
751 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
752 //
753 if (!Found) {
754 return EFI_UNSUPPORTED;
755 }
756
757 //
758 // Search the Unicode String Table for the matching Language specifier
759 //
760 while (UnicodeStringTable->Language != NULL) {
761 LanguageString = UnicodeStringTable->Language;
762 while (0 != *LanguageString) {
763 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
764 if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {
765 *UnicodeString = UnicodeStringTable->UnicodeString;
766 return EFI_SUCCESS;
767 }
768 LanguageString += Index;
769 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);
770 }
771 UnicodeStringTable++;
772 }
773
774 return EFI_UNSUPPORTED;
775 }
776
777
778 /**
779 This function adds a Unicode string to UnicodeStringTable.
780
781 If Language is a member of SupportedLanguages then UnicodeString is added to
782 UnicodeStringTable. New buffers are allocated for both Language and
783 UnicodeString. The contents of Language and UnicodeString are copied into
784 these new buffers. These buffers are automatically freed when
785 FreeUnicodeStringTable() is called.
786
787 @param Language A pointer to the ISO 639-2 language code for the Unicode
788 string to add.
789 @param SupportedLanguages A pointer to the set of ISO 639-2 language codes
790 that the Unicode string table supports.
791 Language must be a member of this set.
792 @param UnicodeStringTable A pointer to the table of Unicode strings.
793 @param UnicodeString A pointer to the Unicode string to add.
794
795 @retval EFI_SUCCESS The Unicode string that matches the language
796 specified by Language was found in the table of
797 Unicode strings UnicodeStringTable, and it was
798 returned in UnicodeString.
799 @retval EFI_INVALID_PARAMETER Language is NULL.
800 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
801 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.
802 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
803 @retval EFI_ALREADY_STARTED A Unicode string with language Language is
804 already present in UnicodeStringTable.
805 @retval EFI_OUT_OF_RESOURCES There is not enough memory to add another
806 Unicode string to UnicodeStringTable.
807 @retval EFI_UNSUPPORTED The language specified by Language is not a
808 member of SupportedLanguages.
809
810 **/
811 EFI_STATUS
812 EFIAPI
813 AddUnicodeString (
814 IN CONST CHAR8 *Language,
815 IN CONST CHAR8 *SupportedLanguages,
816 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,
817 IN CONST CHAR16 *UnicodeString
818 )
819 {
820 UINTN NumberOfEntries;
821 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;
822 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;
823 UINTN UnicodeStringLength;
824
825 //
826 // Make sure the parameter are valid
827 //
828 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
829 return EFI_INVALID_PARAMETER;
830 }
831
832 //
833 // If there are no supported languages, then a Unicode String can not be added
834 //
835 if (SupportedLanguages == NULL) {
836 return EFI_UNSUPPORTED;
837 }
838
839 //
840 // If the Unicode String is empty, then a Unicode String can not be added
841 //
842 if (UnicodeString[0] == 0) {
843 return EFI_INVALID_PARAMETER;
844 }
845
846 //
847 // Make sure Language is a member of SupportedLanguages
848 //
849 while (*SupportedLanguages != 0) {
850 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
851
852 //
853 // Determine the size of the Unicode String Table by looking for a NULL Language entry
854 //
855 NumberOfEntries = 0;
856 if (*UnicodeStringTable != NULL) {
857 OldUnicodeStringTable = *UnicodeStringTable;
858 while (OldUnicodeStringTable->Language != NULL) {
859 if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
860 return EFI_ALREADY_STARTED;
861 }
862
863 OldUnicodeStringTable++;
864 NumberOfEntries++;
865 }
866 }
867
868 //
869 // Allocate space for a new Unicode String Table. It must hold the current number of
870 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
871 // marker
872 //
873 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
874 if (NewUnicodeStringTable == NULL) {
875 return EFI_OUT_OF_RESOURCES;
876 }
877
878 //
879 // If the current Unicode String Table contains any entries, then copy them to the
880 // newly allocated Unicode String Table.
881 //
882 if (*UnicodeStringTable != NULL) {
883 CopyMem (
884 NewUnicodeStringTable,
885 *UnicodeStringTable,
886 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
887 );
888 }
889
890 //
891 // Allocate space for a copy of the Language specifier
892 //
893 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
894 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
895 gBS->FreePool (NewUnicodeStringTable);
896 return EFI_OUT_OF_RESOURCES;
897 }
898
899 //
900 // Compute the length of the Unicode String
901 //
902 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
903 ;
904
905 //
906 // Allocate space for a copy of the Unicode String
907 //
908 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
909 (UnicodeStringLength + 1) * sizeof (CHAR16),
910 UnicodeString
911 );
912 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
913 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
914 gBS->FreePool (NewUnicodeStringTable);
915 return EFI_OUT_OF_RESOURCES;
916 }
917
918 //
919 // Mark the end of the Unicode String Table
920 //
921 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;
922 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
923
924 //
925 // Free the old Unicode String Table
926 //
927 if (*UnicodeStringTable != NULL) {
928 gBS->FreePool (*UnicodeStringTable);
929 }
930
931 //
932 // Point UnicodeStringTable at the newly allocated Unicode String Table
933 //
934 *UnicodeStringTable = NewUnicodeStringTable;
935
936 return EFI_SUCCESS;
937 }
938
939 SupportedLanguages += 3;
940 }
941
942 return EFI_UNSUPPORTED;
943 }
944
945
946 /**
947 This function adds a Unicode string to UnicodeStringTable.
948
949 If Language is a member of SupportedLanguages then
950 UnicodeString is added to UnicodeStringTable. New buffers are
951 allocated for both Language and UnicodeString. The contents
952 of Language and UnicodeString are copied into these new
953 buffers. These buffers are automatically freed when
954 FreeUnicodeStringTable() is called.
955
956 @param Language A pointer to the ISO 639-2 or
957 RFC 3066 language code for the
958 Unicode string to add.
959 @param SupportedLanguages A pointer to the set of ISO
960 639-2 or RFC 3066 language
961 codes that the Unicode string
962 table supports. Language must
963 be a member of this set.
964 @param UnicodeStringTable A pointer to the table of
965 Unicode strings.
966 @param UnicodeString A pointer to the Unicode
967 string to add.
968 @param Iso639Language Specify the language code
969 format supported. If true,
970 then the format follow ISO
971 639-2. If false, then it
972 follows RFC3066.
973 @retval EFI_SUCCESS The Unicode string that
974 matches the language specified
975 by Language was found in the
976 table of Unicode strings
977 UnicodeStringTable, and it was
978 returned in UnicodeString.
979
980 @retval EFI_INVALID_PARAMETER Language is NULL.
981 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
982 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.
983 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
984 @retval EFI_ALREADY_STARTED A Unicode string with language
985 Language is already present in
986 UnicodeStringTable.
987 @retval EFI_OUT_OF_RESOURCES There is not enough memory to
988 add another Unicode string to
989 UnicodeStringTable.
990 @retval EFI_UNSUPPORTED The language specified by
991 Language is not a member of
992 SupportedLanguages.
993
994 **/
995 EFI_STATUS
996 EFIAPI
997 AddUnicodeString2 (
998 IN CONST CHAR8 *Language,
999 IN CONST CHAR8 *SupportedLanguages,
1000 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,
1001 IN CONST CHAR16 *UnicodeString,
1002 IN BOOLEAN Iso639Language
1003 )
1004 {
1005 UINTN NumberOfEntries;
1006 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;
1007 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;
1008 UINTN UnicodeStringLength;
1009 BOOLEAN Found;
1010 UINTN Index;
1011 CHAR8 *LanguageString;
1012
1013 //
1014 // Make sure the parameter are valid
1015 //
1016 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
1017 return EFI_INVALID_PARAMETER;
1018 }
1019
1020 //
1021 // If there are no supported languages, then a Unicode String can not be added
1022 //
1023 if (SupportedLanguages == NULL) {
1024 return EFI_UNSUPPORTED;
1025 }
1026
1027 //
1028 // If the Unicode String is empty, then a Unicode String can not be added
1029 //
1030 if (UnicodeString[0] == 0) {
1031 return EFI_INVALID_PARAMETER;
1032 }
1033
1034 //
1035 // Make sure Language is a member of SupportedLanguages
1036 //
1037 Found = FALSE;
1038 while (*SupportedLanguages != 0) {
1039 if (Iso639Language) {
1040 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
1041 Found = TRUE;
1042 break;
1043 }
1044 SupportedLanguages += 3;
1045 } else {
1046 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
1047 if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {
1048 Found = TRUE;
1049 break;
1050 }
1051 SupportedLanguages += Index;
1052 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
1053 }
1054 }
1055
1056 //
1057 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
1058 //
1059 if (!Found) {
1060 return EFI_UNSUPPORTED;
1061 }
1062
1063 //
1064 // Determine the size of the Unicode String Table by looking for a NULL Language entry
1065 //
1066 NumberOfEntries = 0;
1067 if (*UnicodeStringTable != NULL) {
1068 OldUnicodeStringTable = *UnicodeStringTable;
1069 while (OldUnicodeStringTable->Language != NULL) {
1070 LanguageString = OldUnicodeStringTable->Language;
1071
1072 while (*LanguageString != 0) {
1073 for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
1074
1075 if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
1076 return EFI_ALREADY_STARTED;
1077 }
1078 LanguageString += Index;
1079 for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);
1080 }
1081 OldUnicodeStringTable++;
1082 NumberOfEntries++;
1083 }
1084 }
1085
1086 //
1087 // Allocate space for a new Unicode String Table. It must hold the current number of
1088 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
1089 // marker
1090 //
1091 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
1092 if (NewUnicodeStringTable == NULL) {
1093 return EFI_OUT_OF_RESOURCES;
1094 }
1095
1096 //
1097 // If the current Unicode String Table contains any entries, then copy them to the
1098 // newly allocated Unicode String Table.
1099 //
1100 if (*UnicodeStringTable != NULL) {
1101 CopyMem (
1102 NewUnicodeStringTable,
1103 *UnicodeStringTable,
1104 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
1105 );
1106 }
1107
1108 //
1109 // Allocate space for a copy of the Language specifier
1110 //
1111 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);
1112 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
1113 gBS->FreePool (NewUnicodeStringTable);
1114 return EFI_OUT_OF_RESOURCES;
1115 }
1116
1117 //
1118 // Compute the length of the Unicode String
1119 //
1120 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);
1121
1122 //
1123 // Allocate space for a copy of the Unicode String
1124 //
1125 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
1126 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
1127 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
1128 gBS->FreePool (NewUnicodeStringTable);
1129 return EFI_OUT_OF_RESOURCES;
1130 }
1131
1132 //
1133 // Mark the end of the Unicode String Table
1134 //
1135 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;
1136 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
1137
1138 //
1139 // Free the old Unicode String Table
1140 //
1141 if (*UnicodeStringTable != NULL) {
1142 gBS->FreePool (*UnicodeStringTable);
1143 }
1144
1145 //
1146 // Point UnicodeStringTable at the newly allocated Unicode String Table
1147 //
1148 *UnicodeStringTable = NewUnicodeStringTable;
1149
1150 return EFI_SUCCESS;
1151 }
1152
1153 /**
1154 This function frees the table of Unicode strings in UnicodeStringTable.
1155
1156 If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
1157 Otherwise, each language code, and each Unicode string in the Unicode string
1158 table are freed, and EFI_SUCCESS is returned.
1159
1160 @param UnicodeStringTable A pointer to the table of Unicode strings.
1161
1162 @retval EFI_SUCCESS The Unicode string table was freed.
1163
1164 **/
1165 EFI_STATUS
1166 EFIAPI
1167 FreeUnicodeStringTable (
1168 IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable
1169 )
1170 {
1171 UINTN Index;
1172
1173 //
1174 // If the Unicode String Table is NULL, then it is already freed
1175 //
1176 if (UnicodeStringTable == NULL) {
1177 return EFI_SUCCESS;
1178 }
1179
1180 //
1181 // Loop through the Unicode String Table until we reach the end of table marker
1182 //
1183 for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
1184
1185 //
1186 // Free the Language string from the Unicode String Table
1187 //
1188 gBS->FreePool (UnicodeStringTable[Index].Language);
1189
1190 //
1191 // Free the Unicode String from the Unicode String Table
1192 //
1193 if (UnicodeStringTable[Index].UnicodeString != NULL) {
1194 gBS->FreePool (UnicodeStringTable[Index].UnicodeString);
1195 }
1196 }
1197
1198 //
1199 // Free the Unicode String Table itself
1200 //
1201 gBS->FreePool (UnicodeStringTable);
1202
1203 return EFI_SUCCESS;
1204 }
1205
1206 /**
1207 Determine what is the current language setting. The space reserved for Lang
1208 must be at least RFC_3066_ENTRY_SIZE bytes;
1209
1210 If Lang is NULL, then ASSERT.
1211
1212 @param Lang Pointer of system language. Lang will always be filled with a valid RFC 3066
1213 language string. If "PlatformLang" is not set in the system, the default
1214 language specifed by PcdUefiVariableDefaultPlatformLang is returned.
1215
1216 @return EFI_SUCCESS If the EFI Variable with "PlatformLang" is set and return in Lang.
1217 @return EFI_NOT_FOUND If the EFI Variable with "PlatformLang" is not set, but a valid default language is return in Lang.
1218
1219 **/
1220 EFI_STATUS
1221 EFIAPI
1222 GetCurrentLanguage (
1223 OUT CHAR8 *Lang
1224 )
1225 {
1226 EFI_STATUS Status;
1227 UINTN Size;
1228
1229 ASSERT (Lang != NULL);
1230
1231 //
1232 // Get current language setting
1233 //
1234 Size = RFC_3066_ENTRY_SIZE;
1235 Status = gRT->GetVariable (
1236 L"PlatformLang",
1237 &gEfiGlobalVariableGuid,
1238 NULL,
1239 &Size,
1240 Lang
1241 );
1242
1243 if (EFI_ERROR (Status)) {
1244 AsciiStrCpy (Lang, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang));
1245 }
1246
1247 return Status;
1248 }
1249
1250
1251