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