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