1 /** @file
2 
3   This file contains the keyboard processing code to the HII database.
4 
5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 
17 #include "HiiDatabase.h"
18 #include "HiiHandle.h"
19 #include <Library/DebugLib.h>
20 #include <Guid/ZeroGuid.h>
21 
22 CONST CHAR16 FrameworkReservedVarstoreName[] = FRAMEWORK_RESERVED_VARSTORE_NAME;
23 
24 /**
25 
26   This function returns a list of the package handles of the
27   specified type that are currently active in the HII database. The
28   pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package
29   handles to be listed.
30 
31   If HandleBufferLength is NULL, then ASSERT.
32   If HandleBuffer is NULL, the ASSERT.
33   If PackageType is EFI_HII_PACKAGE_TYPE_GUID and PackageGuid is
34   NULL, then ASSERT.
35   If PackageType is not EFI_HII_PACKAGE_TYPE_GUID and PackageGuid is not
36   NULL, then ASSERT.
37 
38 
39   @param PackageType          Specifies the package type of the packages
40                               to list or EFI_HII_PACKAGE_TYPE_ALL for
41                               all packages to be listed.
42 
43   @param PackageGuid          If PackageType is
44                               EFI_HII_PACKAGE_TYPE_GUID, then this is
45                               the pointer to the GUID which must match
46                               the Guid field of
47                               EFI_HII_PACKAGE_GUID_HEADER. Otherwise, it
48                               must be NULL.
49 
50   @param HandleBufferLength   On output, the length of the handle buffer
51                               that is required for the handles found.
52 
53   @param HandleBuffer         On output, an array of EFI_HII_HANDLE  instances returned.
54                               The caller is responcible to free this pointer allocated.
55 
56   @retval EFI_SUCCESS           The matching handles are outputed successfully.
57                                 HandleBufferLength is updated with the actual length.
58   @retval EFI_OUT_OF_RESOURCES  Not enough resource to complete the operation.
59   @retval EFI_NOT_FOUND         No matching handle could not be found in database.
60 **/
61 EFI_STATUS
62 EFIAPI
ListPackageLists(IN UINT8 PackageType,IN CONST EFI_GUID * PackageGuid,IN OUT UINTN * HandleBufferLength,OUT EFI_HII_HANDLE ** HandleBuffer)63 ListPackageLists (
64   IN        UINT8                     PackageType,
65   IN CONST  EFI_GUID                  *PackageGuid,
66   IN OUT    UINTN                     *HandleBufferLength,
67   OUT       EFI_HII_HANDLE            **HandleBuffer
68   )
69 {
70   EFI_STATUS          Status;
71 
72   ASSERT (HandleBufferLength != NULL);
73   ASSERT (HandleBuffer != NULL);
74 
75   *HandleBufferLength = 0;
76   *HandleBuffer       = NULL;
77 
78   if (PackageType == EFI_HII_PACKAGE_TYPE_GUID) {
79     ASSERT (PackageGuid != NULL);
80   } else {
81     ASSERT (PackageGuid == NULL);
82   }
83 
84   Status = mHiiDatabase->ListPackageLists (
85                            mHiiDatabase,
86                            PackageType,
87                            PackageGuid,
88                            HandleBufferLength,
89                            *HandleBuffer
90                            );
91   if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
92     //
93     // No packages is registered to UEFI HII Database, just return.
94     //
95     //
96     return Status;
97   }
98 
99   *HandleBuffer = AllocateZeroPool (*HandleBufferLength);
100 
101   if (*HandleBuffer == NULL) {
102     return EFI_OUT_OF_RESOURCES;
103   }
104 
105   return mHiiDatabase->ListPackageLists (
106                          mHiiDatabase,
107                          PackageType,
108                          PackageGuid,
109                          HandleBufferLength,
110                          *HandleBuffer
111                          );
112 
113 }
114 
115 /**
116   Exports the contents of one or all package lists in the HII database into a buffer.
117 
118   If Handle is not NULL and not a valid EFI_HII_HANDLE registered in the database,
119   then ASSERT.
120   If PackageListHeader is NULL, then ASSERT.
121   If PackageListSize is NULL, then ASSERT.
122 
123   @param  Handle                 The HII Handle.
124   @param  PackageListHeader      A pointer to a buffer that will contain the results of
125                                  the export function.
126   @param  PackageListSize        On output, the length of the buffer that is required for the exported data.
127 
128   @retval EFI_SUCCESS            Package exported.
129 
130   @retval EFI_OUT_OF_RESOURCES   Not enought memory to complete the operations.
131 
132 **/
133 EFI_STATUS
134 EFIAPI
ExportPackageLists(IN EFI_HII_HANDLE Handle,OUT EFI_HII_PACKAGE_LIST_HEADER ** PackageListHeader,OUT UINTN * PackageListSize)135 ExportPackageLists (
136   IN EFI_HII_HANDLE                    Handle,
137   OUT EFI_HII_PACKAGE_LIST_HEADER      **PackageListHeader,
138   OUT UINTN                            *PackageListSize
139   )
140 {
141   EFI_STATUS                       Status;
142   UINTN                            Size;
143   EFI_HII_PACKAGE_LIST_HEADER      *PackageListHdr;
144 
145   ASSERT (PackageListSize != NULL);
146   ASSERT (PackageListHeader != NULL);
147 
148   Size = 0;
149   PackageListHdr = NULL;
150   Status = mHiiDatabase->ExportPackageLists (
151                            mHiiDatabase,
152                            Handle,
153                            &Size,
154                            PackageListHdr
155                            );
156   ASSERT_EFI_ERROR (Status != EFI_BUFFER_TOO_SMALL);
157 
158   if (Status == EFI_BUFFER_TOO_SMALL) {
159     PackageListHdr = AllocateZeroPool (Size);
160 
161     if (PackageListHeader == NULL) {
162       return EFI_OUT_OF_RESOURCES;
163     } else {
164       Status = mHiiDatabase->ExportPackageLists (
165                                mHiiDatabase,
166                                Handle,
167                                &Size,
168                                PackageListHdr
169                                );
170     }
171   }
172 
173   if (!EFI_ERROR (Status)) {
174     *PackageListHeader = PackageListHdr;
175     *PackageListSize   = Size;
176   } else {
177     FreePool (PackageListHdr);
178   }
179 
180   return Status;
181 }
182 
183 /**
184   Extract Hii package list GUID for given HII handle.
185 
186   If HiiHandle could not be found in the HII database, then ASSERT.
187   If Guid is NULL, then ASSERT.
188 
189   @param  Handle              Hii handle
190   @param  Guid                Package list GUID
191 
192   @retval EFI_SUCCESS            Successfully extract GUID from Hii database.
193 
194 **/
195 EFI_STATUS
196 EFIAPI
ExtractGuidFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT EFI_GUID * Guid)197 ExtractGuidFromHiiHandle (
198   IN      EFI_HII_HANDLE      Handle,
199   OUT     EFI_GUID            *Guid
200   )
201 {
202   EFI_STATUS                   Status;
203   UINTN                        BufferSize;
204   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
205 
206   ASSERT (Guid != NULL);
207   ASSERT (Handle != NULL);
208 
209   //
210   // Get HII PackageList
211   //
212   BufferSize = 0;
213   HiiPackageList = NULL;
214 
215   Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
216   ASSERT (Status != EFI_NOT_FOUND);
217 
218   if (Status == EFI_BUFFER_TOO_SMALL) {
219     HiiPackageList = AllocatePool (BufferSize);
220     ASSERT (HiiPackageList != NULL);
221 
222     Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
223   }
224   if (EFI_ERROR (Status)) {
225     FreePool (HiiPackageList);
226     return Status;
227   }
228 
229   //
230   // Extract GUID
231   //
232   CopyGuid (Guid, &HiiPackageList->PackageListGuid);
233 
234   FreePool (HiiPackageList);
235 
236   return EFI_SUCCESS;
237 }
238 
239 /**
240   Find the corressponding UEFI HII Handle from a Framework HII Handle given.
241 
242   @param Private      The HII Thunk Module Private context.
243   @param FwHiiHandle  The Framemwork HII Handle.
244 
245   @return NULL        If Framework HII Handle is invalid.
246   @return The corresponding UEFI HII Handle.
247 **/
248 EFI_HII_HANDLE
FwHiiHandleToUefiHiiHandle(IN CONST HII_THUNK_PRIVATE_DATA * Private,IN FRAMEWORK_EFI_HII_HANDLE FwHiiHandle)249 FwHiiHandleToUefiHiiHandle (
250   IN CONST HII_THUNK_PRIVATE_DATA      *Private,
251   IN FRAMEWORK_EFI_HII_HANDLE          FwHiiHandle
252   )
253 {
254   HII_THUNK_CONTEXT            *ThunkContext;
255 
256   ASSERT (FwHiiHandle != (FRAMEWORK_EFI_HII_HANDLE) 0);
257   ASSERT (Private != NULL);
258 
259   ThunkContext = FwHiiHandleToThunkContext (Private, FwHiiHandle);
260 
261   if (ThunkContext != NULL) {
262     return ThunkContext->UefiHiiHandle;
263   }
264 
265   return (EFI_HII_HANDLE) NULL;
266 }
267 
268 
269 /**
270   Find the corressponding HII Thunk Context from a Framework HII Handle given.
271 
272   @param Private      The HII Thunk Module Private context.
273   @param FwHiiHandle  The Framemwork HII Handle.
274 
275   @return NULL        If Framework HII Handle is invalid.
276   @return The corresponding HII Thunk Context.
277 **/
278 HII_THUNK_CONTEXT *
FwHiiHandleToThunkContext(IN CONST HII_THUNK_PRIVATE_DATA * Private,IN FRAMEWORK_EFI_HII_HANDLE FwHiiHandle)279 FwHiiHandleToThunkContext (
280   IN CONST HII_THUNK_PRIVATE_DATA      *Private,
281   IN FRAMEWORK_EFI_HII_HANDLE          FwHiiHandle
282   )
283 {
284   LIST_ENTRY                 *Link;
285   HII_THUNK_CONTEXT           *ThunkContext;
286 
287 
288   Link = GetFirstNode (&Private->ThunkContextListHead);
289 
290   while (!IsNull (&Private->ThunkContextListHead, Link)) {
291     ThunkContext = HII_THUNK_CONTEXT_FROM_LINK (Link);
292 
293     if (FwHiiHandle == ThunkContext->FwHiiHandle) {
294       return ThunkContext;
295     }
296 
297     Link = GetNextNode (&Private->ThunkContextListHead, Link);
298   }
299 
300   return NULL;
301 }
302 
303 /**
304   Find the corressponding HII Thunk Context from a UEFI HII Handle given.
305 
306   @param Private        The HII Thunk Module Private context.
307   @param UefiHiiHandle  The UEFI HII Handle.
308 
309   @return NULL        If UEFI HII Handle is invalid.
310   @return The corresponding HII Thunk Context.
311 **/
312 HII_THUNK_CONTEXT *
UefiHiiHandleToThunkContext(IN CONST HII_THUNK_PRIVATE_DATA * Private,IN EFI_HII_HANDLE UefiHiiHandle)313 UefiHiiHandleToThunkContext (
314   IN CONST HII_THUNK_PRIVATE_DATA     *Private,
315   IN EFI_HII_HANDLE                   UefiHiiHandle
316   )
317 {
318   LIST_ENTRY                 *Link;
319   HII_THUNK_CONTEXT           *ThunkContext;
320 
321   Link = GetFirstNode (&Private->ThunkContextListHead);
322 
323   while (!IsNull (&Private->ThunkContextListHead, Link)) {
324     ThunkContext = HII_THUNK_CONTEXT_FROM_LINK (Link);
325 
326     if (UefiHiiHandle == ThunkContext->UefiHiiHandle) {
327       return ThunkContext;
328     }
329     Link = GetNextNode (&Private->ThunkContextListHead, Link);
330   }
331 
332   return NULL;
333 }
334 
335 /**
336   Find the corressponding HII Thunk Context from a Tag GUID.
337 
338   @param Private      The HII Thunk Module Private context.
339   @param Guid         The Tag GUID.
340 
341   @return NULL        No HII Thunk Context matched the Tag GUID.
342   @return The corresponding HII Thunk Context.
343 **/
344 HII_THUNK_CONTEXT *
TagGuidToIfrPackThunkContext(IN CONST HII_THUNK_PRIVATE_DATA * Private,IN CONST EFI_GUID * Guid)345 TagGuidToIfrPackThunkContext (
346   IN CONST HII_THUNK_PRIVATE_DATA *Private,
347   IN CONST EFI_GUID                   *Guid
348   )
349 {
350   LIST_ENTRY                 *Link;
351   HII_THUNK_CONTEXT           *ThunkContext;
352 
353   Link = GetFirstNode (&Private->ThunkContextListHead);
354 
355   while (!IsNull (&Private->ThunkContextListHead, Link)) {
356     ThunkContext = HII_THUNK_CONTEXT_FROM_LINK (Link);
357 
358     if (CompareGuid (Guid, &ThunkContext->TagGuid) && (ThunkContext->IfrPackageCount != 0)) {
359       return ThunkContext;
360     }
361 
362     Link = GetNextNode (&Private->ThunkContextListHead, Link);
363   }
364 
365   return NULL;
366 
367 }
368 
369 /**
370   Clean up the HII Thunk Context for a UEFI HII Handle.
371 
372   @param Private        The HII Thunk Module Private context.
373   @param UefiHiiHandle  The UEFI HII Handle.
374 
375 **/
376 VOID
DestroyThunkContextForUefiHiiHandle(IN HII_THUNK_PRIVATE_DATA * Private,IN EFI_HII_HANDLE UefiHiiHandle)377 DestroyThunkContextForUefiHiiHandle (
378   IN HII_THUNK_PRIVATE_DATA     *Private,
379   IN EFI_HII_HANDLE             UefiHiiHandle
380   )
381 {
382   HII_THUNK_CONTEXT     *ThunkContext;
383 
384   ThunkContext = UefiHiiHandleToThunkContext (Private, UefiHiiHandle);
385   ASSERT (ThunkContext != NULL);
386 
387   DestroyThunkContext (ThunkContext);
388 }
389 
390 
391 /**
392   This function create a HII_THUNK_CONTEXT for the input UEFI HiiHandle
393   that is created when a package list registered by a module calling
394   EFI_HII_DATABASE_PROTOCOL.NewPackageList.
395   This function records the PackageListGuid of EFI_HII_PACKAGE_LIST_HEADER
396   into the TagGuid of the created HII_THUNK_CONTEXT.
397 
398   @param UefiHiiHandle  The UEFI HII Handle.
399 
400   @return the new created Hii thunk context.
401 
402 **/
403 HII_THUNK_CONTEXT *
CreateThunkContextForUefiHiiHandle(IN EFI_HII_HANDLE UefiHiiHandle)404 CreateThunkContextForUefiHiiHandle (
405   IN  EFI_HII_HANDLE             UefiHiiHandle
406   )
407 {
408   EFI_STATUS            Status;
409   EFI_GUID              PackageGuid;
410   HII_THUNK_CONTEXT      *ThunkContext;
411 
412   ThunkContext = AllocateZeroPool (sizeof (*ThunkContext));
413   ASSERT (ThunkContext != NULL);
414 
415   ThunkContext->Signature = HII_THUNK_CONTEXT_SIGNATURE;
416 
417   Status = AllocateHiiHandle (&ThunkContext->FwHiiHandle);
418   if (EFI_ERROR (Status)) {
419     return NULL;
420   }
421 
422   ThunkContext->UefiHiiHandle = UefiHiiHandle;
423 
424   Status = ExtractGuidFromHiiHandle (UefiHiiHandle, &PackageGuid);
425   ASSERT_EFI_ERROR (Status);
426 
427   CopyGuid(&ThunkContext->TagGuid, &PackageGuid);
428 
429   return ThunkContext;
430 }
431 
432 
433 /**
434   Get the number of HII Package for a Package type.
435 
436   @param PackageListHeader      The Package List.
437   @param PackageType            The Package Type.
438 
439   @return The number of Package for given type.
440 **/
441 UINTN
GetPackageCountByType(IN CONST EFI_HII_PACKAGE_LIST_HEADER * PackageListHeader,IN UINT8 PackageType)442 GetPackageCountByType (
443   IN CONST EFI_HII_PACKAGE_LIST_HEADER     *PackageListHeader,
444   IN       UINT8                           PackageType
445   )
446 {
447   UINTN                     Count;
448   EFI_HII_PACKAGE_HEADER    *PackageHeader;
449 
450   PackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageListHeader + sizeof (EFI_HII_PACKAGE_LIST_HEADER));
451   Count = 0;
452 
453   while (PackageHeader->Type != EFI_HII_PACKAGE_END) {
454     if (PackageHeader->Type == PackageType ) {
455       Count++;
456     }
457     PackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHeader + PackageHeader->Length);
458   }
459 
460 
461   return Count;
462 }
463 
464 /**
465   Get the Form Package from a Framework Package List.
466 
467   @param Packages               Framework Package List.
468 
469   @return The Form Package Header found.
470 **/
471 EFI_HII_PACKAGE_HEADER *
GetIfrPackage(IN CONST EFI_HII_PACKAGES * Packages)472 GetIfrPackage (
473   IN CONST EFI_HII_PACKAGES               *Packages
474   )
475 {
476   UINTN                         Index;
477   TIANO_AUTOGEN_PACKAGES_HEADER **TianoAutogenPackageHdrArray;
478 
479   ASSERT (Packages != NULL);
480 
481   TianoAutogenPackageHdrArray = (TIANO_AUTOGEN_PACKAGES_HEADER **) (((UINT8 *) &Packages->GuidId) + sizeof (Packages->GuidId));
482 
483   for (Index = 0; Index < Packages->NumberOfPackages; Index++) {
484     //
485     // The current UEFI HII build tool generate a binary in the format defined by
486     // TIANO_AUTOGEN_PACKAGES_HEADER. We assume that all packages generated in
487     // this binary is with same package type. So the returned IfrPackageCount and StringPackageCount
488     // may not be the exact number of valid package number in the binary generated
489     // by HII Build tool.
490     //
491     switch (TianoAutogenPackageHdrArray[Index]->FrameworkPackageHeader.Type) {
492       case EFI_HII_IFR:
493         return &TianoAutogenPackageHdrArray[Index]->PackageHeader;
494         break;
495       case EFI_HII_STRING:
496       case EFI_HII_FONT:
497         break;
498 
499       default:
500         ASSERT (FALSE);
501         return NULL;
502         break;
503     }
504   }
505 
506   return NULL;
507 }
508 
509 /**
510   Get FormSet GUID.
511 
512   ASSERT if no FormSet Opcode is found.
513 
514   @param Packages             Form Framework Package.
515   @param FormSetGuid          Return the FormSet Guid.
516 
517 **/
518 VOID
GetFormSetGuid(IN EFI_HII_PACKAGE_HEADER * Package,OUT EFI_GUID * FormSetGuid)519 GetFormSetGuid (
520   IN  EFI_HII_PACKAGE_HEADER  *Package,
521   OUT EFI_GUID                *FormSetGuid
522   )
523 {
524   UINTN                         Offset;
525   EFI_IFR_OP_HEADER             *OpCode;
526   EFI_IFR_FORM_SET              *FormSet;
527 
528   Offset = sizeof (EFI_HII_PACKAGE_HEADER);
529   while (Offset < Package->Length) {
530     OpCode = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + Offset);
531 
532     switch (OpCode->OpCode) {
533     case EFI_IFR_FORM_SET_OP:
534       FormSet = (EFI_IFR_FORM_SET *) OpCode;
535       CopyGuid (FormSetGuid, (EFI_GUID *)(VOID *)&FormSet->Guid);
536       return;
537 
538       default:
539         break;
540 
541     }
542     Offset += OpCode->Length;
543   }
544 
545   //
546   // A proper IFR must have a formset opcode.
547   //
548   ASSERT (FALSE);
549 
550 }
551 
552 /**
553   Creat a Thunk Context.
554 
555   ASSERT if no FormSet Opcode is found.
556 
557   @param Private             The HII Thunk Private Context.
558   @param StringPackageCount  The String package count.
559   @param IfrPackageCount     The IFR Package count.
560 
561   @return  A newly created Thunk Context.
562   @retval  NULL  No resource to create a new Thunk Context.
563 **/
564 HII_THUNK_CONTEXT *
CreateThunkContext(IN HII_THUNK_PRIVATE_DATA * Private,IN UINTN StringPackageCount,IN UINTN IfrPackageCount)565 CreateThunkContext (
566   IN  HII_THUNK_PRIVATE_DATA      *Private,
567   IN  UINTN                       StringPackageCount,
568   IN  UINTN                       IfrPackageCount
569   )
570 {
571   EFI_STATUS                   Status;
572   HII_THUNK_CONTEXT            *ThunkContext;
573 
574   ThunkContext = AllocateZeroPool (sizeof (HII_THUNK_CONTEXT));
575   ASSERT (ThunkContext != NULL);
576 
577   ThunkContext->Signature = HII_THUNK_CONTEXT_SIGNATURE;
578   ThunkContext->IfrPackageCount = IfrPackageCount;
579   ThunkContext->StringPackageCount = StringPackageCount;
580   Status = AllocateHiiHandle (&ThunkContext->FwHiiHandle);
581   if (EFI_ERROR (Status)) {
582     return NULL;
583   }
584 
585   return ThunkContext;
586 
587 }
588 
589 /**
590   Destroy the Thunk Context and free up all resource.
591 
592   @param ThunkContext        The HII Thunk Private Context to be freed.
593 
594 **/
595 VOID
DestroyThunkContext(IN HII_THUNK_CONTEXT * ThunkContext)596 DestroyThunkContext (
597   IN HII_THUNK_CONTEXT          *ThunkContext
598   )
599 {
600   ASSERT (ThunkContext != NULL);
601 
602   FreeHiiHandle (ThunkContext->FwHiiHandle);
603 
604   RemoveEntryList (&ThunkContext->Link);
605 
606   if (ThunkContext->FormSet != NULL) {
607     DestroyFormSet (ThunkContext->FormSet);
608   }
609 
610   FreePool (ThunkContext);
611 }
612 
613 /**
614   Get the FormSet's Default Varstore ID based on the rule (Descending Priority):
615 
616   1) If VarStore ID of FRAMEWORK_RESERVED_VARSTORE_ID (0x01) is found, Var Store ID is used.
617   2) If VarStore ID of FRAMEWORK_RESERVED_VARSTORE_ID is not found, First Var Store ID is used
618      as the default Var Store ID.
619 
620   @param FormSet The Form Set. The Default Varstore ID is updated if found.
621 
622 **/
623 VOID
GetFormsetDefaultVarstoreId(IN OUT FORM_BROWSER_FORMSET * FormSet)624 GetFormsetDefaultVarstoreId (
625   IN OUT FORM_BROWSER_FORMSET  * FormSet
626   )
627 {
628   LIST_ENTRY             *StorageList;
629   FORMSET_STORAGE        *Storage;
630 
631   //
632   // VarStoreId 0 is invalid in UEFI IFR.
633   //
634   FormSet->DefaultVarStoreId = 0;
635   StorageList = GetFirstNode (&FormSet->StorageListHead);
636 
637   while (!IsNull (&FormSet->StorageListHead, StorageList)) {
638     Storage = FORMSET_STORAGE_FROM_LINK (StorageList);
639 
640     DEBUG ((EFI_D_INFO, "FormSet %g: Found Varstore ID %x Name %s Size 0x%x\n", &FormSet->Guid, Storage->VarStoreId, Storage->Name, Storage->Size));
641 
642     if (Storage->VarStoreId == FRAMEWORK_RESERVED_VARSTORE_ID) {
643       //
644       // 1) If VarStore ID of FRAMEWORK_RESERVED_VARSTORE_ID (0x01) is found, Var Store ID is used.
645       //
646       FormSet->DefaultVarStoreId = FRAMEWORK_RESERVED_VARSTORE_ID;
647       break;
648     }
649 
650     StorageList = GetNextNode (&FormSet->StorageListHead, StorageList);
651   }
652 
653   if (FormSet->DefaultVarStoreId != FRAMEWORK_RESERVED_VARSTORE_ID) {
654     //
655     //
656     // 2) If VarStore ID of FRAMEWORK_RESERVED_VARSTORE_ID is not found, First Var Store ID is used
657     //   as the default Var Store ID.
658     //
659     StorageList = GetFirstNode (&FormSet->StorageListHead);
660     if (!IsNull (&FormSet->StorageListHead, StorageList)) {
661       Storage = FORMSET_STORAGE_FROM_LINK (StorageList);
662       FormSet->DefaultVarStoreId = Storage->VarStoreId;
663     }
664 
665   }
666 
667   if (FormSet->DefaultVarStoreId == 0) {
668     DEBUG ((EFI_D_INFO, "FormSet %g: No Varstore Found\n", &FormSet->Guid));
669   }
670 
671   return;
672 }
673 
674 /**
675   Fetch the Ifr binary data of a FormSet.
676 
677   @param  Handle                 PackageList Handle
678   @param  FormSetGuid            GUID of a formset. If not specified (NULL or zero
679                                  GUID), take the first FormSet found in package
680                                  list.
681   @param  BinaryLength           The length of the FormSet IFR binary.
682   @param  BinaryData             The buffer designed to receive the FormSet.
683 
684   @retval EFI_SUCCESS            Buffer filled with the requested FormSet.
685                                  BufferLength was updated.
686   @retval EFI_INVALID_PARAMETER  The handle is unknown.
687   @retval EFI_NOT_FOUND          A form or FormSet on the requested handle cannot
688                                  be found with the requested FormId.
689 
690 **/
691 EFI_STATUS
GetIfrBinaryData(IN EFI_HII_HANDLE Handle,IN OUT EFI_GUID * FormSetGuid,OUT UINTN * BinaryLength,OUT UINT8 ** BinaryData)692 GetIfrBinaryData (
693   IN  EFI_HII_HANDLE   Handle,
694   IN OUT EFI_GUID      *FormSetGuid,
695   OUT UINTN            *BinaryLength,
696   OUT UINT8            **BinaryData
697   )
698 {
699   EFI_STATUS                   Status;
700   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
701   UINTN                        BufferSize;
702   UINT8                        *Package;
703   UINT8                        *OpCodeData;
704   UINT32                       Offset;
705   UINT32                       Offset2;
706   BOOLEAN                      ReturnDefault;
707   UINT32                       PackageListLength;
708   EFI_HII_PACKAGE_HEADER       PackageHeader;
709 
710   OpCodeData = NULL;
711   Package = NULL;
712   ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));;
713 
714   //
715   // if FormSetGuid is NULL or zero GUID, return first FormSet in the package list
716   //
717   if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) {
718     ReturnDefault = TRUE;
719   } else {
720     ReturnDefault = FALSE;
721   }
722 
723   //
724   // Get HII PackageList
725   //
726   BufferSize = 0;
727   HiiPackageList = NULL;
728   Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
729   if (Status == EFI_BUFFER_TOO_SMALL) {
730     HiiPackageList = AllocatePool (BufferSize);
731     ASSERT (HiiPackageList != NULL);
732 
733     Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList);
734   }
735   if (EFI_ERROR (Status) || HiiPackageList == NULL) {
736     return EFI_NOT_FOUND;
737   }
738 
739   //
740   // Get Form package from this HII package List
741   //
742   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
743   Offset2 = 0;
744   CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
745 
746   while (Offset < PackageListLength) {
747     Package = ((UINT8 *) HiiPackageList) + Offset;
748     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
749 
750     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
751       //
752       // Search FormSet in this Form Package
753       //
754       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
755       while (Offset2 < PackageHeader.Length) {
756         OpCodeData = Package + Offset2;
757 
758         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
759           //
760           // Check whether return default FormSet
761           //
762           if (ReturnDefault) {
763             break;
764           }
765 
766           //
767           // FormSet GUID is specified, check it
768           //
769           if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
770             break;
771           }
772         }
773 
774         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
775       }
776 
777       if (Offset2 < PackageHeader.Length) {
778         //
779         // Target formset found
780         //
781         break;
782       }
783     }
784 
785     Offset += PackageHeader.Length;
786   }
787 
788   if (Offset >= PackageListLength) {
789     //
790     // Form package not found in this Package List
791     //
792     gBS->FreePool (HiiPackageList);
793     return EFI_NOT_FOUND;
794   }
795 
796   if (ReturnDefault && FormSetGuid != NULL) {
797     //
798     // Return the default FormSet GUID
799     //
800     CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID));
801   }
802 
803   //
804   // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes
805   // in this FormSet; So, here just simply copy the data from start of a FormSet to the end
806   // of the Form Package.
807   //
808   *BinaryLength = PackageHeader.Length - Offset2;
809   *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData);
810 
811   gBS->FreePool (HiiPackageList);
812 
813   if (*BinaryData == NULL) {
814     return EFI_OUT_OF_RESOURCES;
815   }
816 
817   return EFI_SUCCESS;
818 }
819 
820 /**
821   Initialize the internal data structure of a FormSet.
822 
823   @param  Handle                 PackageList Handle
824   @param  FormSetGuid            GUID of a formset. If not specified (NULL or zero
825                                  GUID), take the first FormSet found in package
826                                  list.
827   @param  FormSet                FormSet data structure.
828 
829   @retval EFI_SUCCESS            The function completed successfully.
830   @retval EFI_NOT_FOUND          The specified FormSet could not be found.
831 
832 **/
833 EFI_STATUS
InitializeFormSet(IN EFI_HII_HANDLE Handle,IN OUT EFI_GUID * FormSetGuid,OUT FORM_BROWSER_FORMSET * FormSet)834 InitializeFormSet (
835   IN  EFI_HII_HANDLE                   Handle,
836   IN OUT EFI_GUID                      *FormSetGuid,
837   OUT FORM_BROWSER_FORMSET             *FormSet
838   )
839 {
840   EFI_STATUS                Status;
841 
842   Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);
843   if (EFI_ERROR (Status)) {
844     return Status;
845   }
846 
847   FormSet->HiiHandle = Handle;
848   CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));
849 
850   //
851   // Parse the IFR binary OpCodes
852   //
853   Status = ParseOpCodes (FormSet);
854   if (EFI_ERROR (Status)) {
855     return Status;
856   }
857 
858   GetFormsetDefaultVarstoreId (FormSet);
859   return Status;
860 }
861 
862 /**
863   Parse the Form Package and build a FORM_BROWSER_FORMSET structure.
864 
865   @param  UefiHiiHandle          PackageList Handle
866 
867   @return A pointer to FORM_BROWSER_FORMSET.
868 
869 **/
870 FORM_BROWSER_FORMSET *
ParseFormSet(IN EFI_HII_HANDLE UefiHiiHandle)871 ParseFormSet (
872   IN EFI_HII_HANDLE   UefiHiiHandle
873   )
874 {
875   FORM_BROWSER_FORMSET  *FormSet;
876   EFI_GUID              FormSetGuid;
877   EFI_STATUS            Status;
878 
879   FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
880   ASSERT (FormSet != NULL);
881 
882   CopyGuid (&FormSetGuid, &gZeroGuid);
883   Status = InitializeFormSet (UefiHiiHandle, &FormSetGuid, FormSet);
884   if (EFI_ERROR (Status)) {
885     FreePool (FormSet);
886     return NULL;
887   }
888 
889   return FormSet;
890 }
891 
892