2 Implement protocol interface related to package registrations.
4 Copyright (c) 2006 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "HiiDatabase.h"
19 STATIC BOOLEAN mInFrameworkHiiNewPack
= FALSE
;
20 STATIC BOOLEAN mInFrameworkHiiRemovePack
= FALSE
;
21 BOOLEAN mInFrameworkUpdatePakcage
= FALSE
;
26 IN CONST EFI_HII_PACKAGES
*Packages
,
27 UINTN
*IfrPackageCount
,
28 UINTN
*StringPackageCount
32 TIANO_AUTOGEN_PACKAGES_HEADER
**TianoAutogenPackageHdrArray
;
34 ASSERT (Packages
!= NULL
);
35 ASSERT (IfrPackageCount
!= NULL
);
36 ASSERT (StringPackageCount
!= NULL
);
39 *StringPackageCount
= 0;
41 TianoAutogenPackageHdrArray
= (TIANO_AUTOGEN_PACKAGES_HEADER
**) (((UINT8
*) &Packages
->GuidId
) + sizeof (Packages
->GuidId
));
43 for (Index
= 0; Index
< Packages
->NumberOfPackages
; Index
++) {
45 // BugBug: The current UEFI HII build tool generate a binary in the format defined in:
46 // TIANO_AUTOGEN_PACKAGES_HEADER. We assume that all packages generated in
47 // this binary is with same package type. So the returned IfrPackageCount and StringPackageCount
48 // may not be the exact number of valid package number in the binary generated
51 switch (TianoAutogenPackageHdrArray
[Index
]->PackageHeader
.Type
) {
52 case EFI_HII_PACKAGE_FORM
:
53 *IfrPackageCount
+= 1;
55 case EFI_HII_PACKAGE_STRINGS
:
56 *StringPackageCount
+= 1;
59 case EFI_HII_PACKAGE_SIMPLE_FONTS
:
63 // The following fonts are invalid for a module that using Framework to UEFI thunk layer.
65 case EFI_HII_PACKAGE_KEYBOARD_LAYOUT
:
66 case EFI_HII_PACKAGE_FONTS
:
67 case EFI_HII_PACKAGE_IMAGES
:
70 return EFI_INVALID_PARAMETER
;
79 Removes a node from a doubly linked list, and returns the node that follows
82 Removes the node Entry from a doubly linked list. It is up to the caller of
83 this function to release the memory used by this node if that is required. On
84 exit, the node following Entry in the doubly linked list is returned. If
85 Entry is the only node in the linked list, then the head node of the linked
88 If Entry is NULL, then ASSERT().
89 If Entry is the head node of an empty list, then ASSERT().
90 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
91 linked list containing Entry, including the Entry node, is greater than
92 or equal to PcdMaximumLinkedListLength, then ASSERT().
94 @param Entry A pointer to a node in a linked list
100 FindPackListWithOnlyIfrPackAndAddStringPack (
101 IN HII_THUNK_PRIVATE_DATA
*Private
,
102 IN HII_THUNK_CONTEXT
*StringPackageThunkContext
,
103 IN CONST EFI_HII_PACKAGE_LIST_HEADER
*StringPackageListHeader
108 HII_THUNK_CONTEXT
*ThunkContext
;
110 Link
= GetFirstNode (&Private
->ThunkContextListHead
);
111 while (!IsNull (&Private
->ThunkContextListHead
, Link
)) {
113 ThunkContext
= HII_THUNK_CONTEXT_FROM_LINK (Link
);
115 if (StringPackageThunkContext
!= ThunkContext
) {
117 // Skip the String Package Thunk Entry itself.
120 if (CompareGuid (&StringPackageListHeader
->PackageListGuid
, &ThunkContext
->TagGuid
)) {
122 ASSERT (ThunkContext
->StringPackageCount
== 0 && ThunkContext
->IfrPackageCount
== 1);
124 ThunkContext
->StringPackageCount
= GetPackageCountByType (StringPackageListHeader
, EFI_HII_PACKAGE_STRINGS
);
126 Status
= mHiiDatabase
->UpdatePackageList (
128 ThunkContext
->UefiHiiHandle
,
129 StringPackageListHeader
131 ASSERT (Status
!= EFI_NOT_FOUND
);
133 if (EFI_ERROR (Status
)) {
139 Link
= GetNextNode (&Private
->ThunkContextListHead
, Link
);
143 return EFI_NOT_FOUND
;
147 EFI_HII_PACKAGE_LIST_HEADER
*
148 PrepareUefiPackageListFromFrameworkHiiPackages (
149 IN CONST EFI_HII_PACKAGES
*Packages
,
150 IN CONST EFI_GUID
*PackageListGuid
153 UINTN NumberOfPackages
;
154 EFI_HII_PACKAGE_LIST_HEADER
*PackageListHeader
;
155 UINT8
*PackageListData
;
156 UINT32 PackageListLength
;
157 UINT32 PackageLength
;
158 EFI_HII_PACKAGE_HEADER PackageHeader
;
160 TIANO_AUTOGEN_PACKAGES_HEADER
**TianoAutogenPackageHdrArray
;
162 ASSERT (Packages
!= NULL
);
163 ASSERT (PackageListGuid
!= NULL
);
165 TianoAutogenPackageHdrArray
= (TIANO_AUTOGEN_PACKAGES_HEADER
**) ((UINT8
*) &Packages
->GuidId
+ sizeof (Packages
->GuidId
));
166 NumberOfPackages
= Packages
->NumberOfPackages
;
168 PackageListLength
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
170 for (Index
= 0; Index
< NumberOfPackages
; Index
++) {
171 CopyMem (&PackageLength
, &TianoAutogenPackageHdrArray
[Index
]->BinaryLength
, sizeof (UINT32
));
173 //TIANO_AUTOGEN_PACKAGES_HEADER.BinaryLength include the BinaryLength itself.
175 PackageListLength
+= (PackageLength
- sizeof(UINT32
));
179 // Include the lenght of EFI_HII_PACKAGE_END
181 PackageListLength
+= sizeof (EFI_HII_PACKAGE_HEADER
);
182 PackageListHeader
= AllocateZeroPool (PackageListLength
);
183 ASSERT (PackageListHeader
!= NULL
);
185 CopyMem (&PackageListHeader
->PackageListGuid
, PackageListGuid
, sizeof (EFI_GUID
));
186 PackageListHeader
->PackageLength
= PackageListLength
;
188 PackageListData
= ((UINT8
*) PackageListHeader
) + sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
190 for (Index
= 0; Index
< NumberOfPackages
; Index
++) {
191 CopyMem (&PackageLength
, &(TianoAutogenPackageHdrArray
[Index
]->BinaryLength
), sizeof (UINT32
));
192 PackageLength
-= sizeof (UINT32
);
193 CopyMem (PackageListData
, &(TianoAutogenPackageHdrArray
[Index
]->PackageHeader
), PackageLength
);
194 PackageListData
+= PackageLength
;
198 // Append EFI_HII_PACKAGE_END
200 PackageHeader
.Type
= EFI_HII_PACKAGE_END
;
201 PackageHeader
.Length
= sizeof (EFI_HII_PACKAGE_HEADER
);
202 CopyMem (PackageListData
, &PackageHeader
, PackageHeader
.Length
);
204 return PackageListHeader
;
209 IN CONST EFI_GUID
* InGuid
,
210 OUT EFI_GUID
* OutGuid
213 UINT64 MonotonicCount
;
215 CopyMem (OutGuid
, InGuid
, sizeof (EFI_GUID
));
217 gBS
->GetNextMonotonicCount (&MonotonicCount
);
219 // Use Monotonic Count as a psedo random number generator.
221 *((UINT64
*) OutGuid
) = *((UINT64
*) OutGuid
) + MonotonicCount
;
225 FindStringPackAndAddToPackListWithOnlyIfrPack(
226 IN HII_THUNK_PRIVATE_DATA
*Private
,
227 IN HII_THUNK_CONTEXT
*IfrThunkContext
232 EFI_HII_PACKAGE_LIST_HEADER
*StringPackageListHeader
;
234 HII_THUNK_CONTEXT
*ThunkContext
;
237 Link
= GetFirstNode (&Private
->ThunkContextListHead
);
239 while (!IsNull (&Private
->ThunkContextListHead
, Link
)) {
241 ThunkContext
= HII_THUNK_CONTEXT_FROM_LINK (Link
);
243 if (ThunkContext
!= IfrThunkContext
) {
244 if (CompareGuid (&IfrThunkContext
->TagGuid
, &ThunkContext
->TagGuid
) && (ThunkContext
->IfrPackageCount
== 0)) {
245 Status
= HiiLibExportPackageLists (ThunkContext
->UefiHiiHandle
, &StringPackageListHeader
, &Size
);
246 ASSERT_EFI_ERROR (Status
);
248 IfrThunkContext
->StringPackageCount
= GetPackageCountByType (StringPackageListHeader
, EFI_HII_PACKAGE_STRINGS
);
250 // Add Function to only get only String Packages from the Package List
252 Status
= mHiiDatabase
->UpdatePackageList (
254 IfrThunkContext
->UefiHiiHandle
,
255 StringPackageListHeader
257 ASSERT_EFI_ERROR (Status
);
259 FreePool (StringPackageListHeader
);
264 Link
= GetNextNode (&Private
->ThunkContextListHead
, Link
);
267 return EFI_NOT_FOUND
;
273 IN HII_THUNK_PRIVATE_DATA
*Private
,
274 IN UINTN StringPackageCount
,
275 IN UINTN IfrPackageCount
279 HII_THUNK_CONTEXT
*ThunkContext
;
281 ThunkContext
= AllocateZeroPool (sizeof (HII_THUNK_CONTEXT
));
282 ASSERT (ThunkContext
!= NULL
);
284 ThunkContext
->Signature
= HII_THUNK_CONTEXT_SIGNATURE
;
285 ThunkContext
->IfrPackageCount
= IfrPackageCount
;
286 ThunkContext
->StringPackageCount
= StringPackageCount
;
287 Status
= AssignFrameworkHiiHandle (Private
, TRUE
, &ThunkContext
->FwHiiHandle
);
288 if (EFI_ERROR (Status
)) {
292 InitializeListHead (&ThunkContext
->QuestionIdMapListHead
);
293 InitializeListHead (&ThunkContext
->OneOfOptionMapListHead
);
301 FreeFrameworkHiiHandle (
302 IN HII_THUNK_PRIVATE_DATA
*Private
,
303 IN FRAMEWORK_EFI_HII_HANDLE FwHandle
314 DestoryOneOfOptionMap (
315 IN LIST_ENTRY
*OneOfOptionMapListHead
318 ONE_OF_OPTION_MAP
*Map
;
319 ONE_OF_OPTION_MAP_ENTRY
*MapEntry
;
323 while (!IsListEmpty (OneOfOptionMapListHead
)) {
324 Link
= GetFirstNode (OneOfOptionMapListHead
);
326 Map
= ONE_OF_OPTION_MAP_FROM_LINK (Link
);
328 while (!IsListEmpty (&Map
->OneOfOptionMapEntryListHead
)) {
329 Link2
= GetFirstNode (&Map
->OneOfOptionMapEntryListHead
);
331 MapEntry
= ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link
);
333 RemoveEntryList (Link2
);
338 RemoveEntryList (Link
);
344 DestroyQuestionIdMap (
345 IN LIST_ENTRY
*QuestionIdMapListHead
348 QUESTION_ID_MAP
*IdMap
;
349 QUESTION_ID_MAP_ENTRY
*IdMapEntry
;
353 while (!IsListEmpty (QuestionIdMapListHead
)) {
354 Link
= GetFirstNode (QuestionIdMapListHead
);
356 IdMap
= QUESTION_ID_MAP_FROM_LINK (Link
);
358 while (!IsListEmpty (&IdMap
->MapEntryListHead
)) {
359 Link2
= GetFirstNode (&IdMap
->MapEntryListHead
);
361 IdMapEntry
= QUESTION_ID_MAP_ENTRY_FROM_LINK (Link
);
363 RemoveEntryList (Link2
);
365 FreePool (IdMapEntry
);
368 RemoveEntryList (Link
);
374 DestroyThunkContext (
375 IN HII_THUNK_PRIVATE_DATA
*Private
,
376 IN HII_THUNK_CONTEXT
*ThunkContext
379 ASSERT (ThunkContext
!= NULL
);
381 FreeFrameworkHiiHandle (Private
, ThunkContext
->FwHiiHandle
);
383 DestroyQuestionIdMap (&ThunkContext
->QuestionIdMapListHead
);
385 DestoryOneOfOptionMap (&ThunkContext
->OneOfOptionMapListHead
);
387 FreePool (ThunkContext
);
390 CONST EFI_GUID mAGuid
=
391 { 0x14f95e01, 0xd562, 0x432e, { 0x84, 0x4a, 0x95, 0xa4, 0x39, 0x5, 0x10, 0x7e } };
394 UefiRegisterPackageList(
395 IN HII_THUNK_PRIVATE_DATA
*Private
,
396 IN EFI_HII_PACKAGES
*Packages
,
397 OUT FRAMEWORK_EFI_HII_HANDLE
*Handle
401 UINTN StringPackageCount
;
402 UINTN IfrPackageCount
;
403 EFI_HII_PACKAGE_LIST_HEADER
*PackageListHeader
;
404 HII_THUNK_CONTEXT
*ThunkContext
;
407 PackageListHeader
= NULL
;
409 Status
= GetPackageCount (Packages
, &IfrPackageCount
, &StringPackageCount
);
410 ASSERT_EFI_ERROR (Status
);
412 if (IfrPackageCount
> 1) {
414 // HII Thunk only handle package with 0 or 1 IFR package.
416 return EFI_UNSUPPORTED
;
419 ThunkContext
= CreateThunkContext (Private
, StringPackageCount
, IfrPackageCount
);
420 if (ThunkContext
== NULL
) {
421 return EFI_OUT_OF_RESOURCES
;
424 if (Packages
->GuidId
== NULL
) {
426 // UEFI HII Database require Package List GUID must be unique.
428 // If Packages->GuidId is NULL, the caller of FramworkHii->NewPack is registering
429 // packages with at least 1 StringPack and 1 IfrPack. Therefore, Packages->GuidId is
430 // not used as the name of the package list. A GUID is generated as a Package List
433 ASSERT (StringPackageCount
>=1 && IfrPackageCount
== 1);
434 Packages
->GuidId
= &GuidId
;
435 GenerateGuidId (&mAGuid
, Packages
->GuidId
);
437 //BugBug We need fix this.
438 //ASSERT (StringPackageCount == 0 || IfrPackageCount == 0);
439 CopyGuid (&GuidId
, Packages
->GuidId
);
443 // Record the Package List GUID, it is used as a name for the package list by Framework HII.
445 CopyGuid (&ThunkContext
->TagGuid
, Packages
->GuidId
);
447 if ((StringPackageCount
== 0) && (IfrPackageCount
!= 0)) {
449 // UEFI HII database does not allow two package list with the same GUID.
450 // In Framework HII implementation, Packages->GuidId is used as an identifier to associate
451 // a PackageList with only IFR to a Package list the with String package.
453 GenerateGuidId (Packages
->GuidId
, &GuidId
);
457 // UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so
458 // that Setup Utility can load the Buffer Storage using this protocol.
460 if (IfrPackageCount
!= 0) {
461 InstallDefaultConfigAccessProtocol (Packages
, ThunkContext
);
463 PackageListHeader
= PrepareUefiPackageListFromFrameworkHiiPackages (Packages
, &GuidId
);
464 Status
= mHiiDatabase
->NewPackageList (
467 ThunkContext
->UefiHiiDriverHandle
,
468 &ThunkContext
->UefiHiiHandle
472 // BUGBUG: Remove when development is done
474 ASSERT_EFI_ERROR (Status
);
475 if (EFI_ERROR (Status
)) {
479 if (IfrPackageCount
== 0) {
480 if (StringPackageCount
!= 0) {
482 // Find if there is Package List with only IFR Package in the databasee with the same
483 // tag. If found, add the String Package to this Package List.
485 Status
= FindPackListWithOnlyIfrPackAndAddStringPack (
491 if (Status
== EFI_NOT_FOUND
) {
492 Status
= EFI_SUCCESS
;
496 CreateQuestionIdMap (ThunkContext
);
498 if (StringPackageCount
== 0) {
500 // Register the Package List to UEFI HII first.
502 Status
= FindStringPackAndAddToPackListWithOnlyIfrPack (
506 ASSERT_EFI_ERROR (Status
);
511 if (EFI_ERROR (Status
)) {
512 DestroyThunkContext (Private
, ThunkContext
);
514 InsertTailList (&Private
->ThunkContextListHead
, &ThunkContext
->Link
);
515 *Handle
= ThunkContext
->FwHiiHandle
;
518 SafeFreePool (PackageListHeader
);
527 IN EFI_HII_PROTOCOL
*This
,
528 IN EFI_HII_PACKAGES
*Packages
,
529 OUT FRAMEWORK_EFI_HII_HANDLE
*Handle
535 Extracts the various packs from a package list.
539 This - Pointer of HII protocol.
540 Packages - Pointer of HII packages.
541 Handle - Handle value to be returned.
545 EFI_SUCCESS - Pacakges has added to HII database successfully.
546 EFI_INVALID_PARAMETER - Invalid parameter.
551 HII_THUNK_PRIVATE_DATA
*Private
;
554 if (Handle
== NULL
) {
555 return EFI_INVALID_PARAMETER
;
558 if (Packages
== NULL
) {
559 return EFI_INVALID_PARAMETER
;
562 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
565 // We use a simple Global variable to inform NewPackNotify
566 // that the package list registered here is already registered
567 // in the HII Thunk Layer. So NewPackNotify does not need to
568 // call RegisterUefiHiiHandle () to registered it.
570 mInFrameworkHiiNewPack
= TRUE
;
572 Private
= HII_THUNK_PRIVATE_DATA_FROM_THIS(This
);
574 Status
= UefiRegisterPackageList (
580 mInFrameworkHiiNewPack
= FALSE
;
582 gBS
->RestoreTPL (OldTpl
);
590 IN EFI_HII_PROTOCOL
*This
,
591 IN FRAMEWORK_EFI_HII_HANDLE Handle
596 Removes the various packs from a Handle
605 HII_THUNK_PRIVATE_DATA
*Private
;
606 HII_THUNK_CONTEXT
*ThunkContext
;
609 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
611 mInFrameworkHiiRemovePack
= TRUE
;
613 Private
= HII_THUNK_PRIVATE_DATA_FROM_THIS(This
);
615 ThunkContext
= FwHiiHandleToThunkContext (Private
, Handle
);
617 if (ThunkContext
!= NULL
) {
618 Status
= mHiiDatabase
->RemovePackageList (
620 ThunkContext
->UefiHiiHandle
622 ASSERT_EFI_ERROR (Status
);
624 if (ThunkContext
->IfrPackageCount
!= 0) {
625 UninstallDefaultConfigAccessProtocol (ThunkContext
);
628 RemoveEntryList (&ThunkContext
->Link
);
630 DestroyThunkContext (Private
, ThunkContext
);
632 Status
= EFI_NOT_FOUND
;
635 mInFrameworkHiiRemovePack
= FALSE
;
637 gBS
->RestoreTPL (OldTpl
);
645 IN UINT8 PackageType
,
646 IN CONST EFI_GUID
*PackageGuid
,
647 IN CONST EFI_HII_PACKAGE_HEADER
*Package
,
648 IN EFI_HII_HANDLE Handle
,
649 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
653 HII_THUNK_PRIVATE_DATA
*Private
;
654 HII_THUNK_CONTEXT
*ThunkContext
;
656 ASSERT (PackageType
== EFI_HII_PACKAGE_STRINGS
|| PackageType
== EFI_HII_PACKAGE_FORM
);
657 ASSERT (NotifyType
== EFI_HII_DATABASE_NOTIFY_ADD_PACK
|| NotifyType
== EFI_HII_DATABASE_NOTIFY_NEW_PACK
);
659 Status
= EFI_SUCCESS
;
660 Private
= mHiiThunkPrivateData
;
662 if (mInFrameworkHiiNewPack
|| mInFrameworkUpdatePakcage
) {
667 // We only create a ThunkContext if the Uefi Hii Handle is only already registered
668 // by the HII Thunk Layer.
670 ThunkContext
= UefiHiiHandleToThunkContext (Private
, Handle
);
671 if (ThunkContext
== NULL
) {
672 ThunkContext
= CreateThunkContextForUefiHiiHandle (Private
, Handle
);
673 ASSERT (ThunkContext
!= NULL
);
677 if (PackageType
== EFI_HII_PACKAGE_FORM
) {
678 Status
= CreateQuestionIdMap (ThunkContext
);
686 IsRemovingLastStringPack (
687 IN EFI_HII_HANDLE Handle
690 EFI_HII_PACKAGE_LIST_HEADER
*HiiPackageList
;
693 EFI_HII_PACKAGE_HEADER
*PackageHeader
;
694 UINTN StringPackageCount
;
696 HiiPackageList
= NULL
;
698 StringPackageCount
= 0;
700 Status
= HiiLibExportPackageLists (Handle
, &HiiPackageList
, &BufferSize
);
701 ASSERT_EFI_ERROR (Status
);
703 PackageHeader
= (EFI_HII_PACKAGE_HEADER
*) ((UINT8
*) HiiPackageList
+ sizeof (EFI_HII_PACKAGE_LIST_HEADER
));
705 while (PackageHeader
->Type
!= EFI_HII_PACKAGE_END
) {
706 switch (PackageHeader
->Type
) {
707 case EFI_HII_PACKAGE_STRINGS
:
708 StringPackageCount
++;
710 if (StringPackageCount
> 1) {
712 // More than one String Pack in the package list
714 FreePool (HiiPackageList
);
723 // goto header of next package
725 PackageHeader
= (EFI_HII_PACKAGE_HEADER
*) ((UINT8
*) PackageHeader
+ PackageHeader
->Length
);
730 // We will always be notified for the removal of String Pack from a package list.
731 // So StringPackageCount must be one at this point.
733 ASSERT (StringPackageCount
== 1);
735 FreePool (HiiPackageList
);
741 // Framework HII module may cache a GUID as the name of the package list.
742 // Then search for the Framework HII handle database for the handle matching
748 IN UINT8 PackageType
,
749 IN CONST EFI_GUID
*PackageGuid
,
750 IN CONST EFI_HII_PACKAGE_HEADER
*Package
,
751 IN EFI_HII_HANDLE Handle
,
752 IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
756 HII_THUNK_PRIVATE_DATA
*Private
;
757 HII_THUNK_CONTEXT
* ThunkContext
;
759 Status
= EFI_SUCCESS
;
761 ASSERT (PackageType
== EFI_HII_PACKAGE_STRINGS
);
762 ASSERT (NotifyType
== EFI_HII_DATABASE_NOTIFY_REMOVE_PACK
);
764 if (mInFrameworkHiiRemovePack
|| mInFrameworkUpdatePakcage
) {
768 Private
= mHiiThunkPrivateData
;
770 ThunkContext
= UefiHiiHandleToThunkContext (Private
, Handle
);
772 if (ThunkContext
->FwHiiHandle
> Private
->StaticHiiHandle
) {
773 if (IsRemovingLastStringPack (Handle
)) {
775 // If the string package will be removed is the last string package
776 // in the package list, we will remove the HII Thunk entry from the
779 Status
= DestroyThunkContextForUefiHiiHandle (Private
, Handle
);