]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/UefiLib/UefiLib.c
Update copyright for files modified in this year
[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.
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 @return The current TPL.
293
294 **/
295 EFI_TPL
296 EFIAPI
297 EfiGetCurrentTpl (
298 VOID
299 )
300 {
301 EFI_TPL Tpl;
302
303 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
304 gBS->RestoreTPL (Tpl);
305
306 return Tpl;
307 }
308
309
310 /**
311 Initializes a basic mutual exclusion lock.
312
313 This function initializes a basic mutual exclusion lock to the released state
314 and returns the lock. Each lock provides mutual exclusion access at its task
315 priority level. Since there is no preemption or multiprocessor support in EFI,
316 acquiring the lock only consists of raising to the locks TPL.
317 If Lock is NULL, then ASSERT().
318 If Priority is not a valid TPL value, then ASSERT().
319
320 @param Lock A pointer to the lock data structure to initialize.
321 @param Priority EFI TPL associated with the lock.
322
323 @return The lock.
324
325 **/
326 EFI_LOCK *
327 EFIAPI
328 EfiInitializeLock (
329 IN OUT EFI_LOCK *Lock,
330 IN EFI_TPL Priority
331 )
332 {
333 ASSERT (Lock != NULL);
334 ASSERT (Priority <= TPL_HIGH_LEVEL);
335
336 Lock->Tpl = Priority;
337 Lock->OwnerTpl = TPL_APPLICATION;
338 Lock->Lock = EfiLockReleased ;
339 return Lock;
340 }
341
342 /**
343 Acquires ownership of a lock.
344
345 This function raises the system's current task priority level to the task
346 priority level of the mutual exclusion lock. Then, it places the lock in the
347 acquired state.
348 If Lock is NULL, then ASSERT().
349 If Lock is not initialized, then ASSERT().
350 If Lock is already in the acquired state, then ASSERT().
351
352 @param Lock A pointer to the lock to acquire.
353
354 **/
355 VOID
356 EFIAPI
357 EfiAcquireLock (
358 IN EFI_LOCK *Lock
359 )
360 {
361 ASSERT (Lock != NULL);
362 ASSERT (Lock->Lock == EfiLockReleased);
363
364 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
365 Lock->Lock = EfiLockAcquired;
366 }
367
368 /**
369 Acquires ownership of a lock.
370
371 This function raises the system's current task priority level to the task priority
372 level of the mutual exclusion lock. Then, it attempts to place the lock in the acquired state.
373 If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
374 Otherwise, EFI_SUCCESS is returned.
375 If Lock is NULL, then ASSERT().
376 If Lock is not initialized, then ASSERT().
377
378 @param Lock A pointer to the lock to acquire.
379
380 @retval EFI_SUCCESS The lock was acquired.
381 @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
382
383 **/
384 EFI_STATUS
385 EFIAPI
386 EfiAcquireLockOrFail (
387 IN EFI_LOCK *Lock
388 )
389 {
390
391 ASSERT (Lock != NULL);
392 ASSERT (Lock->Lock != EfiLockUninitialized);
393
394 if (Lock->Lock == EfiLockAcquired) {
395 //
396 // Lock is already owned, so bail out
397 //
398 return EFI_ACCESS_DENIED;
399 }
400
401 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
402
403 Lock->Lock = EfiLockAcquired;
404
405 return EFI_SUCCESS;
406 }
407
408 /**
409 Releases ownership of a lock.
410
411 This function transitions a mutual exclusion lock from the acquired state to
412 the released state, and restores the system's task priority level to its
413 previous level.
414 If Lock is NULL, then ASSERT().
415 If Lock is not initialized, then ASSERT().
416 If Lock is already in the released state, then ASSERT().
417
418 @param Lock A pointer to the lock to release.
419
420 **/
421 VOID
422 EFIAPI
423 EfiReleaseLock (
424 IN EFI_LOCK *Lock
425 )
426 {
427 EFI_TPL Tpl;
428
429 ASSERT (Lock != NULL);
430 ASSERT (Lock->Lock == EfiLockAcquired);
431
432 Tpl = Lock->OwnerTpl;
433
434 Lock->Lock = EfiLockReleased;
435
436 gBS->RestoreTPL (Tpl);
437 }
438
439 /**
440 Tests whether a controller handle is being managed by a specific driver.
441
442 This function tests whether the driver specified by DriverBindingHandle is
443 currently managing the controller specified by ControllerHandle. This test
444 is performed by evaluating if the the protocol specified by ProtocolGuid is
445 present on ControllerHandle and is was opened by DriverBindingHandle with an
446 attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
447 If ProtocolGuid is NULL, then ASSERT().
448
449 @param ControllerHandle A handle for a controller to test.
450 @param DriverBindingHandle Specifies the driver binding handle for the
451 driver.
452 @param ProtocolGuid Specifies the protocol that the driver specified
453 by DriverBindingHandle opens in its Start()
454 function.
455
456 @retval EFI_SUCCESS ControllerHandle is managed by the driver
457 specifed by DriverBindingHandle.
458 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
459 specifed by DriverBindingHandle.
460
461 **/
462 EFI_STATUS
463 EFIAPI
464 EfiTestManagedDevice (
465 IN CONST EFI_HANDLE ControllerHandle,
466 IN CONST EFI_HANDLE DriverBindingHandle,
467 IN CONST EFI_GUID *ProtocolGuid
468 )
469 {
470 EFI_STATUS Status;
471 VOID *ManagedInterface;
472
473 ASSERT (ProtocolGuid != NULL);
474
475 Status = gBS->OpenProtocol (
476 ControllerHandle,
477 (EFI_GUID *) ProtocolGuid,
478 &ManagedInterface,
479 DriverBindingHandle,
480 ControllerHandle,
481 EFI_OPEN_PROTOCOL_BY_DRIVER
482 );
483 if (!EFI_ERROR (Status)) {
484 gBS->CloseProtocol (
485 ControllerHandle,
486 (EFI_GUID *) ProtocolGuid,
487 DriverBindingHandle,
488 ControllerHandle
489 );
490 return EFI_UNSUPPORTED;
491 }
492
493 if (Status != EFI_ALREADY_STARTED) {
494 return EFI_UNSUPPORTED;
495 }
496
497 return EFI_SUCCESS;
498 }
499
500 /**
501 Tests whether a child handle is a child device of the controller.
502
503 This function tests whether ChildHandle is one of the children of
504 ControllerHandle. This test is performed by checking to see if the protocol
505 specified by ProtocolGuid is present on ControllerHandle and opened by
506 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
507 If ProtocolGuid is NULL, then ASSERT().
508
509 @param ControllerHandle A handle for a (parent) controller to test.
510 @param ChildHandle A child handle to test.
511 @param ProtocolGuid Supplies the protocol that the child controller
512 opens on its parent controller.
513
514 @retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle.
515 @retval EFI_UNSUPPORTED ChildHandle is not a child of the
516 ControllerHandle.
517
518 **/
519 EFI_STATUS
520 EFIAPI
521 EfiTestChildHandle (
522 IN CONST EFI_HANDLE ControllerHandle,
523 IN CONST EFI_HANDLE ChildHandle,
524 IN CONST EFI_GUID *ProtocolGuid
525 )
526 {
527 EFI_STATUS Status;
528 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
529 UINTN EntryCount;
530 UINTN Index;
531
532 ASSERT (ProtocolGuid != NULL);
533
534 //
535 // Retrieve the list of agents that are consuming the specific protocol
536 // on ControllerHandle.
537 //
538 Status = gBS->OpenProtocolInformation (
539 ControllerHandle,
540 (EFI_GUID *) ProtocolGuid,
541 &OpenInfoBuffer,
542 &EntryCount
543 );
544 if (EFI_ERROR (Status)) {
545 return EFI_UNSUPPORTED;
546 }
547
548 //
549 // Inspect if ChildHandle is one of the agents.
550 //
551 Status = EFI_UNSUPPORTED;
552 for (Index = 0; Index < EntryCount; Index++) {
553 if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
554 (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
555 Status = EFI_SUCCESS;
556 break;
557 }
558 }
559
560 FreePool (OpenInfoBuffer);
561 return Status;
562 }
563
564 /**
565 This function looks up a Unicode string in UnicodeStringTable.
566
567 If Language is a member of SupportedLanguages and a Unicode string is found in
568 UnicodeStringTable that matches the language code specified by Language, then it
569 is returned in UnicodeString.
570
571 @param Language A pointer to the ISO 639-2 language code for the
572 Unicode string to look up and return.
573 @param SupportedLanguages A pointer to the set of ISO 639-2 language codes
574 that the Unicode string table supports. Language
575 must be a member of this set.
576 @param UnicodeStringTable A pointer to the table of Unicode strings.
577 @param UnicodeString A pointer to the Unicode string from UnicodeStringTable
578 that matches the language specified by Language.
579
580 @retval EFI_SUCCESS The Unicode string that matches the language
581 specified by Language was found
582 in the table of Unicoide strings UnicodeStringTable,
583 and it was returned in UnicodeString.
584 @retval EFI_INVALID_PARAMETER Language is NULL.
585 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
586 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
587 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.
588 @retval EFI_UNSUPPORTED The language specified by Language is not a
589 member of SupportedLanguages.
590 @retval EFI_UNSUPPORTED The language specified by Language is not
591 supported by UnicodeStringTable.
592
593 **/
594 EFI_STATUS
595 EFIAPI
596 LookupUnicodeString (
597 IN CONST CHAR8 *Language,
598 IN CONST CHAR8 *SupportedLanguages,
599 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,
600 OUT CHAR16 **UnicodeString
601 )
602 {
603 //
604 // Make sure the parameters are valid
605 //
606 if (Language == NULL || UnicodeString == NULL) {
607 return EFI_INVALID_PARAMETER;
608 }
609
610 //
611 // If there are no supported languages, or the Unicode String Table is empty, then the
612 // Unicode String specified by Language is not supported by this Unicode String Table
613 //
614 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
615 return EFI_UNSUPPORTED;
616 }
617
618 //
619 // Make sure Language is in the set of Supported Languages
620 //
621 while (*SupportedLanguages != 0) {
622 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
623
624 //
625 // Search the Unicode String Table for the matching Language specifier
626 //
627 while (UnicodeStringTable->Language != NULL) {
628 if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
629
630 //
631 // A matching string was found, so return it
632 //
633 *UnicodeString = UnicodeStringTable->UnicodeString;
634 return EFI_SUCCESS;
635 }
636
637 UnicodeStringTable++;
638 }
639
640 return EFI_UNSUPPORTED;
641 }
642
643 SupportedLanguages += 3;
644 }
645
646 return EFI_UNSUPPORTED;
647 }
648
649
650
651 /**
652 This function looks up a Unicode string in UnicodeStringTable.
653
654 If Language is a member of SupportedLanguages and a Unicode string is found in
655 UnicodeStringTable that matches the language code specified by Language, then
656 it is returned in UnicodeString.
657
658 @param Language A pointer to an ASCII string containing the ISO 639-2 or the
659 RFC 4646 language code for the Unicode string to look up and
660 return. If Iso639Language is TRUE, then this ASCII string is
661 not assumed to be Null-terminated, and only the first three
662 chacters are used. If Iso639Language is FALSE, then this ASCII
663 string must be Null-terminated.
664 @param SupportedLanguages A pointer to a Null-terminated ASCII string that contains a
665 set of ISO 639-2 or RFC 4646 language codes that the Unicode
666 string table supports. Language must be a member of this set.
667 If Iso639Language is TRUE, then this string contains one or more
668 ISO 639-2 language codes with no separator characters. If Iso639Language
669 is FALSE, then is string contains one or more RFC 4646 language
670 codes separated by ';'.
671 @param UnicodeStringTable A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
672 is defined in "Related Definitions".
673 @param UnicodeString A pointer to the Null-terminated Unicode string from UnicodeStringTable
674 that matches the language specified by Language.
675 @param Iso639Language Specifies the supported language code format. If it is TRUE, then
676 Language and SupportedLanguages follow ISO 639-2 language code format.
677 Otherwise, they follow RFC 4646 language code format.
678
679
680 @retval EFI_SUCCESS The Unicode string that matches the language specified by Language
681 was found in the table of Unicode strings UnicodeStringTable, and
682 it was returned in UnicodeString.
683 @retval EFI_INVALID_PARAMETER Language is NULL.
684 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
685 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
686 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.
687 @retval EFI_UNSUPPORTED The language specified by Language is not a member of SupportedLanguages.
688 @retval EFI_UNSUPPORTED The language specified by Language is not supported by UnicodeStringTable.
689
690 **/
691 EFI_STATUS
692 EFIAPI
693 LookupUnicodeString2 (
694 IN CONST CHAR8 *Language,
695 IN CONST CHAR8 *SupportedLanguages,
696 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,
697 OUT CHAR16 **UnicodeString,
698 IN BOOLEAN Iso639Language
699 )
700 {
701 BOOLEAN Found;
702 UINTN Index;
703 CHAR8 *LanguageString;
704
705 //
706 // Make sure the parameters are valid
707 //
708 if (Language == NULL || UnicodeString == NULL) {
709 return EFI_INVALID_PARAMETER;
710 }
711
712 //
713 // If there are no supported languages, or the Unicode String Table is empty, then the
714 // Unicode String specified by Language is not supported by this Unicode String Table
715 //
716 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
717 return EFI_UNSUPPORTED;
718 }
719
720 //
721 // Make sure Language is in the set of Supported Languages
722 //
723 Found = FALSE;
724 while (*SupportedLanguages != 0) {
725 if (Iso639Language) {
726 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
727 Found = TRUE;
728 break;
729 }
730 SupportedLanguages += 3;
731 } else {
732 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
733 if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
734 Found = TRUE;
735 break;
736 }
737 SupportedLanguages += Index;
738 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
739 }
740 }
741
742 //
743 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
744 //
745 if (!Found) {
746 return EFI_UNSUPPORTED;
747 }
748
749 //
750 // Search the Unicode String Table for the matching Language specifier
751 //
752 while (UnicodeStringTable->Language != NULL) {
753 LanguageString = UnicodeStringTable->Language;
754 while (0 != *LanguageString) {
755 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
756 if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {
757 *UnicodeString = UnicodeStringTable->UnicodeString;
758 return EFI_SUCCESS;
759 }
760 LanguageString += Index;
761 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);
762 }
763 UnicodeStringTable++;
764 }
765
766 return EFI_UNSUPPORTED;
767 }
768
769
770 /**
771 This function adds a Unicode string to UnicodeStringTable.
772
773 If Language is a member of SupportedLanguages then UnicodeString is added to
774 UnicodeStringTable. New buffers are allocated for both Language and
775 UnicodeString. The contents of Language and UnicodeString are copied into
776 these new buffers. These buffers are automatically freed when
777 FreeUnicodeStringTable() is called.
778
779 @param Language A pointer to the ISO 639-2 language code for the Unicode
780 string to add.
781 @param SupportedLanguages A pointer to the set of ISO 639-2 language codes
782 that the Unicode string table supports.
783 Language must be a member of this set.
784 @param UnicodeStringTable A pointer to the table of Unicode strings.
785 @param UnicodeString A pointer to the Unicode string to add.
786
787 @retval EFI_SUCCESS The Unicode string that matches the language
788 specified by Language was found in the table of
789 Unicode strings UnicodeStringTable, and it was
790 returned in UnicodeString.
791 @retval EFI_INVALID_PARAMETER Language is NULL.
792 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
793 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.
794 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
795 @retval EFI_ALREADY_STARTED A Unicode string with language Language is
796 already present in UnicodeStringTable.
797 @retval EFI_OUT_OF_RESOURCES There is not enough memory to add another
798 Unicode string to UnicodeStringTable.
799 @retval EFI_UNSUPPORTED The language specified by Language is not a
800 member of SupportedLanguages.
801
802 **/
803 EFI_STATUS
804 EFIAPI
805 AddUnicodeString (
806 IN CONST CHAR8 *Language,
807 IN CONST CHAR8 *SupportedLanguages,
808 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,
809 IN CONST CHAR16 *UnicodeString
810 )
811 {
812 UINTN NumberOfEntries;
813 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;
814 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;
815 UINTN UnicodeStringLength;
816
817 //
818 // Make sure the parameter are valid
819 //
820 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
821 return EFI_INVALID_PARAMETER;
822 }
823
824 //
825 // If there are no supported languages, then a Unicode String can not be added
826 //
827 if (SupportedLanguages == NULL) {
828 return EFI_UNSUPPORTED;
829 }
830
831 //
832 // If the Unicode String is empty, then a Unicode String can not be added
833 //
834 if (UnicodeString[0] == 0) {
835 return EFI_INVALID_PARAMETER;
836 }
837
838 //
839 // Make sure Language is a member of SupportedLanguages
840 //
841 while (*SupportedLanguages != 0) {
842 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
843
844 //
845 // Determine the size of the Unicode String Table by looking for a NULL Language entry
846 //
847 NumberOfEntries = 0;
848 if (*UnicodeStringTable != NULL) {
849 OldUnicodeStringTable = *UnicodeStringTable;
850 while (OldUnicodeStringTable->Language != NULL) {
851 if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
852 return EFI_ALREADY_STARTED;
853 }
854
855 OldUnicodeStringTable++;
856 NumberOfEntries++;
857 }
858 }
859
860 //
861 // Allocate space for a new Unicode String Table. It must hold the current number of
862 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
863 // marker
864 //
865 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
866 if (NewUnicodeStringTable == NULL) {
867 return EFI_OUT_OF_RESOURCES;
868 }
869
870 //
871 // If the current Unicode String Table contains any entries, then copy them to the
872 // newly allocated Unicode String Table.
873 //
874 if (*UnicodeStringTable != NULL) {
875 CopyMem (
876 NewUnicodeStringTable,
877 *UnicodeStringTable,
878 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
879 );
880 }
881
882 //
883 // Allocate space for a copy of the Language specifier
884 //
885 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
886 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
887 gBS->FreePool (NewUnicodeStringTable);
888 return EFI_OUT_OF_RESOURCES;
889 }
890
891 //
892 // Compute the length of the Unicode String
893 //
894 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
895 ;
896
897 //
898 // Allocate space for a copy of the Unicode String
899 //
900 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
901 (UnicodeStringLength + 1) * sizeof (CHAR16),
902 UnicodeString
903 );
904 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
905 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
906 gBS->FreePool (NewUnicodeStringTable);
907 return EFI_OUT_OF_RESOURCES;
908 }
909
910 //
911 // Mark the end of the Unicode String Table
912 //
913 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;
914 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
915
916 //
917 // Free the old Unicode String Table
918 //
919 if (*UnicodeStringTable != NULL) {
920 gBS->FreePool (*UnicodeStringTable);
921 }
922
923 //
924 // Point UnicodeStringTable at the newly allocated Unicode String Table
925 //
926 *UnicodeStringTable = NewUnicodeStringTable;
927
928 return EFI_SUCCESS;
929 }
930
931 SupportedLanguages += 3;
932 }
933
934 return EFI_UNSUPPORTED;
935 }
936
937
938 /**
939 This function adds the Null-terminated Unicode string specified by UnicodeString
940 to UnicodeStringTable.
941
942 If Language is a member of SupportedLanguages then UnicodeString is added to
943 UnicodeStringTable. New buffers are allocated for both Language and UnicodeString.
944 The contents of Language and UnicodeString are copied into these new buffers.
945 These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called.
946
947 @param Language A pointer to an ASCII string containing the ISO 639-2 or
948 the RFC 4646 language code for the Unicode string to add.
949 If Iso639Language is TRUE, then this ASCII string is not
950 assumed to be Null-terminated, and only the first three
951 chacters are used. If Iso639Language is FALSE, then this
952 ASCII string must be Null-terminated.
953 @param SupportedLanguages A pointer to a Null-terminated ASCII string that contains
954 a set of ISO 639-2 or RFC 4646 language codes that the Unicode
955 string table supports. Language must be a member of this set.
956 If Iso639Language is TRUE, then this string contains one or more
957 ISO 639-2 language codes with no separator characters.
958 If Iso639Language is FALSE, then is string contains one or more
959 RFC 4646 language codes separated by ';'.
960 @param UnicodeStringTable A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
961 is defined in "Related Definitions".
962 @param UnicodeString A pointer to the Unicode string to add.
963 @param Iso639Language Specifies the supported language code format. If it is TRUE,
964 then Language and SupportedLanguages follow ISO 639-2 language code format.
965 Otherwise, they follow RFC 4646 language code format.
966
967 @retval EFI_SUCCESS The Unicode string that matches the language specified by
968 Language was found in the table of Unicode strings UnicodeStringTable,
969 and it was returned in UnicodeString.
970 @retval EFI_INVALID_PARAMETER Language is NULL.
971 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.
972 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.
973 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.
974 @retval EFI_ALREADY_STARTED A Unicode string with language Language is already present in
975 UnicodeStringTable.
976 @retval EFI_OUT_OF_RESOURCES There is not enough memory to add another Unicode string UnicodeStringTable.
977 @retval EFI_UNSUPPORTED The language specified by Language is not a member of SupportedLanguages.
978
979 **/
980 EFI_STATUS
981 EFIAPI
982 AddUnicodeString2 (
983 IN CONST CHAR8 *Language,
984 IN CONST CHAR8 *SupportedLanguages,
985 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,
986 IN CONST CHAR16 *UnicodeString,
987 IN BOOLEAN Iso639Language
988 )
989 {
990 UINTN NumberOfEntries;
991 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;
992 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;
993 UINTN UnicodeStringLength;
994 BOOLEAN Found;
995 UINTN Index;
996 CHAR8 *LanguageString;
997
998 //
999 // Make sure the parameter are valid
1000 //
1001 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
1002 return EFI_INVALID_PARAMETER;
1003 }
1004
1005 //
1006 // If there are no supported languages, then a Unicode String can not be added
1007 //
1008 if (SupportedLanguages == NULL) {
1009 return EFI_UNSUPPORTED;
1010 }
1011
1012 //
1013 // If the Unicode String is empty, then a Unicode String can not be added
1014 //
1015 if (UnicodeString[0] == 0) {
1016 return EFI_INVALID_PARAMETER;
1017 }
1018
1019 //
1020 // Make sure Language is a member of SupportedLanguages
1021 //
1022 Found = FALSE;
1023 while (*SupportedLanguages != 0) {
1024 if (Iso639Language) {
1025 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
1026 Found = TRUE;
1027 break;
1028 }
1029 SupportedLanguages += 3;
1030 } else {
1031 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
1032 if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {
1033 Found = TRUE;
1034 break;
1035 }
1036 SupportedLanguages += Index;
1037 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
1038 }
1039 }
1040
1041 //
1042 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
1043 //
1044 if (!Found) {
1045 return EFI_UNSUPPORTED;
1046 }
1047
1048 //
1049 // Determine the size of the Unicode String Table by looking for a NULL Language entry
1050 //
1051 NumberOfEntries = 0;
1052 if (*UnicodeStringTable != NULL) {
1053 OldUnicodeStringTable = *UnicodeStringTable;
1054 while (OldUnicodeStringTable->Language != NULL) {
1055 LanguageString = OldUnicodeStringTable->Language;
1056
1057 while (*LanguageString != 0) {
1058 for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
1059
1060 if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
1061 return EFI_ALREADY_STARTED;
1062 }
1063 LanguageString += Index;
1064 for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);
1065 }
1066 OldUnicodeStringTable++;
1067 NumberOfEntries++;
1068 }
1069 }
1070
1071 //
1072 // Allocate space for a new Unicode String Table. It must hold the current number of
1073 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
1074 // marker
1075 //
1076 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
1077 if (NewUnicodeStringTable == NULL) {
1078 return EFI_OUT_OF_RESOURCES;
1079 }
1080
1081 //
1082 // If the current Unicode String Table contains any entries, then copy them to the
1083 // newly allocated Unicode String Table.
1084 //
1085 if (*UnicodeStringTable != NULL) {
1086 CopyMem (
1087 NewUnicodeStringTable,
1088 *UnicodeStringTable,
1089 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
1090 );
1091 }
1092
1093 //
1094 // Allocate space for a copy of the Language specifier
1095 //
1096 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);
1097 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
1098 gBS->FreePool (NewUnicodeStringTable);
1099 return EFI_OUT_OF_RESOURCES;
1100 }
1101
1102 //
1103 // Compute the length of the Unicode String
1104 //
1105 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);
1106
1107 //
1108 // Allocate space for a copy of the Unicode String
1109 //
1110 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
1111 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
1112 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
1113 gBS->FreePool (NewUnicodeStringTable);
1114 return EFI_OUT_OF_RESOURCES;
1115 }
1116
1117 //
1118 // Mark the end of the Unicode String Table
1119 //
1120 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;
1121 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
1122
1123 //
1124 // Free the old Unicode String Table
1125 //
1126 if (*UnicodeStringTable != NULL) {
1127 gBS->FreePool (*UnicodeStringTable);
1128 }
1129
1130 //
1131 // Point UnicodeStringTable at the newly allocated Unicode String Table
1132 //
1133 *UnicodeStringTable = NewUnicodeStringTable;
1134
1135 return EFI_SUCCESS;
1136 }
1137
1138 /**
1139 This function frees the table of Unicode strings in UnicodeStringTable.
1140
1141 If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
1142 Otherwise, each language code, and each Unicode string in the Unicode string
1143 table are freed, and EFI_SUCCESS is returned.
1144
1145 @param UnicodeStringTable A pointer to the table of Unicode strings.
1146
1147 @retval EFI_SUCCESS The Unicode string table was freed.
1148
1149 **/
1150 EFI_STATUS
1151 EFIAPI
1152 FreeUnicodeStringTable (
1153 IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable
1154 )
1155 {
1156 UINTN Index;
1157
1158 //
1159 // If the Unicode String Table is NULL, then it is already freed
1160 //
1161 if (UnicodeStringTable == NULL) {
1162 return EFI_SUCCESS;
1163 }
1164
1165 //
1166 // Loop through the Unicode String Table until we reach the end of table marker
1167 //
1168 for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
1169
1170 //
1171 // Free the Language string from the Unicode String Table
1172 //
1173 gBS->FreePool (UnicodeStringTable[Index].Language);
1174
1175 //
1176 // Free the Unicode String from the Unicode String Table
1177 //
1178 if (UnicodeStringTable[Index].UnicodeString != NULL) {
1179 gBS->FreePool (UnicodeStringTable[Index].UnicodeString);
1180 }
1181 }
1182
1183 //
1184 // Free the Unicode String Table itself
1185 //
1186 gBS->FreePool (UnicodeStringTable);
1187
1188 return EFI_SUCCESS;
1189 }