1 /*++
2 
3 Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   UefiIfrCommon.c
15 
16 Abstract:
17 
18   Common Library Routines to assist handle HII elements.
19 
20 --*/
21 
22 #include "UefiIfrLibrary.h"
23 
24 //
25 // Hii vendor device path template
26 //
27 HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePathTemplate = {
28   {
29     {
30       {
31         HARDWARE_DEVICE_PATH,
32         HW_VENDOR_DP,
33         {
34           (UINT8) (sizeof (HII_VENDOR_DEVICE_PATH_NODE)),
35           (UINT8) ((sizeof (HII_VENDOR_DEVICE_PATH_NODE)) >> 8)
36         }
37       },
38       EFI_IFR_TIANO_GUID,
39     },
40     0,
41     0
42   },
43   {
44     END_DEVICE_PATH_TYPE,
45     END_ENTIRE_DEVICE_PATH_SUBTYPE,
46     {
47       END_DEVICE_PATH_LENGTH
48     }
49   }
50 };
51 
52 //
53 // Hii relative protocols
54 //
55 BOOLEAN  mHiiProtocolsInitialized = FALSE;
56 
57 EFI_HII_DATABASE_PROTOCOL *gIfrLibHiiDatabase;
58 EFI_HII_STRING_PROTOCOL   *gIfrLibHiiString;
59 
60 VOID
LocateHiiProtocols(VOID)61 LocateHiiProtocols (
62   VOID
63   )
64 /*++
65 
66 Routine Description:
67   This function locate Hii relative protocols for later usage.
68 
69 Arguments:
70   None.
71 
72 Returns:
73   None.
74 
75 --*/
76 {
77   EFI_STATUS  Status;
78 
79   if (mHiiProtocolsInitialized) {
80     return;
81   }
82 
83   Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &gIfrLibHiiDatabase);
84   ASSERT_EFI_ERROR (Status);
85 
86   Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &gIfrLibHiiString);
87   ASSERT_EFI_ERROR (Status);
88 
89   mHiiProtocolsInitialized = TRUE;
90 }
91 
92 EFI_HII_PACKAGE_LIST_HEADER *
PreparePackageList(IN UINTN NumberOfPackages,IN EFI_GUID * GuidId,...)93 PreparePackageList (
94   IN UINTN                    NumberOfPackages,
95   IN EFI_GUID                 *GuidId,
96   ...
97   )
98 /*++
99 
100 Routine Description:
101   Assemble EFI_HII_PACKAGE_LIST according to the passed in packages.
102 
103 Arguments:
104   NumberOfPackages  -  Number of packages.
105   GuidId            -  Package GUID.
106 
107 Returns:
108   Pointer of EFI_HII_PACKAGE_LIST_HEADER.
109 
110 --*/
111 {
112   VA_LIST                     Marker;
113   EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;
114   UINT8                       *PackageListData;
115   UINT32                      PackageListLength;
116   UINT32                      PackageLength;
117   EFI_HII_PACKAGE_HEADER      PackageHeader;
118   UINT8                       *PackageArray;
119   UINTN                       Index;
120 
121   PackageListLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
122 
123   VA_START (Marker, GuidId);
124   for (Index = 0; Index < NumberOfPackages; Index++) {
125     EfiCopyMem (&PackageLength, VA_ARG (Marker, VOID *), sizeof (UINT32));
126     PackageListLength += (PackageLength - sizeof (UINT32));
127   }
128   VA_END (Marker);
129 
130   //
131   // Include the lenght of EFI_HII_PACKAGE_END
132   //
133   PackageListLength += sizeof (EFI_HII_PACKAGE_HEADER);
134   PackageListHeader = EfiLibAllocateZeroPool (PackageListLength);
135   ASSERT (PackageListHeader != NULL);
136   EfiCopyMem (&PackageListHeader->PackageListGuid, GuidId, sizeof (EFI_GUID));
137   PackageListHeader->PackageLength = PackageListLength;
138 
139   PackageListData = ((UINT8 *) PackageListHeader) + sizeof (EFI_HII_PACKAGE_LIST_HEADER);
140 
141   VA_START (Marker, GuidId);
142   for (Index = 0; Index < NumberOfPackages; Index++) {
143     PackageArray = (UINT8 *) VA_ARG (Marker, VOID *);
144     EfiCopyMem (&PackageLength, PackageArray, sizeof (UINT32));
145     PackageLength  -= sizeof (UINT32);
146     PackageArray += sizeof (UINT32);
147     EfiCopyMem (PackageListData, PackageArray, PackageLength);
148     PackageListData += PackageLength;
149   }
150   VA_END (Marker);
151 
152   //
153   // Append EFI_HII_PACKAGE_END
154   //
155   PackageHeader.Type = EFI_HII_PACKAGE_END;
156   PackageHeader.Length = sizeof (EFI_HII_PACKAGE_HEADER);
157   EfiCopyMem (PackageListData, &PackageHeader, PackageHeader.Length);
158 
159   return PackageListHeader;
160 }
161 
162 EFI_STATUS
CreateHiiDriverHandle(OUT EFI_HANDLE * DriverHandle)163 CreateHiiDriverHandle (
164   OUT EFI_HANDLE               *DriverHandle
165   )
166 /*++
167 
168 Routine Description:
169   The HII driver handle passed in for HiiDatabase.NewPackageList() requires
170   that there should be DevicePath Protocol installed on it.
171   This routine create a virtual Driver Handle by installing a vendor device
172   path on it, so as to use it to invoke HiiDatabase.NewPackageList().
173 
174 Arguments:
175   DriverHandle         - Handle to be returned
176 
177 Returns:
178   EFI_SUCCESS          - Handle destroy success.
179   EFI_OUT_OF_RESOURCES - Not enough memory.
180 
181 --*/
182 {
183   EFI_STATUS                   Status;
184   HII_VENDOR_DEVICE_PATH_NODE  *VendorDevicePath;
185 
186   VendorDevicePath = EfiLibAllocateCopyPool (sizeof (HII_VENDOR_DEVICE_PATH), &mHiiVendorDevicePathTemplate);
187   if (VendorDevicePath == NULL) {
188     return EFI_OUT_OF_RESOURCES;
189   }
190 
191   //
192   // Use memory address as unique ID to distinguish from different device paths
193   //
194   VendorDevicePath->UniqueId = (UINT64) ((UINTN) VendorDevicePath);
195 
196   *DriverHandle = NULL;
197   Status = gBS->InstallMultipleProtocolInterfaces (
198                   DriverHandle,
199                   &gEfiDevicePathProtocolGuid,
200                   VendorDevicePath,
201                   NULL
202                   );
203   if (EFI_ERROR (Status)) {
204     return Status;
205   }
206 
207   return EFI_SUCCESS;
208 }
209 
210 EFI_STATUS
DestroyHiiDriverHandle(IN EFI_HANDLE DriverHandle)211 DestroyHiiDriverHandle (
212   IN EFI_HANDLE                 DriverHandle
213   )
214 /*++
215 
216 Routine Description:
217   Destroy the Driver Handle created by CreateHiiDriverHandle().
218 
219 Arguments:
220   DriverHandle - Handle returned by CreateHiiDriverHandle()
221 
222 Returns:
223   EFI_SUCCESS - Handle destroy success.
224   other       - Handle destroy fail.
225 
226 --*/
227 {
228   EFI_STATUS                   Status;
229   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;
230 
231   Status = gBS->HandleProtocol (
232                   DriverHandle,
233                   &gEfiDevicePathProtocolGuid,
234                   (VOID **) &DevicePath
235                   );
236   if (EFI_ERROR (Status)) {
237     return Status;
238   }
239 
240   Status = gBS->UninstallProtocolInterface (
241                   DriverHandle,
242                   &gEfiDevicePathProtocolGuid,
243                   DevicePath
244                   );
245   gBS->FreePool (DevicePath);
246   return Status;
247 }
248 
249 EFI_HII_HANDLE
DevicePathToHiiHandle(IN EFI_HII_DATABASE_PROTOCOL * HiiDatabase,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)250 DevicePathToHiiHandle (
251   IN EFI_HII_DATABASE_PROTOCOL  *HiiDatabase,
252   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
253   )
254 /*++
255 
256 Routine Description:
257   Find HII Handle associated with given Device Path.
258 
259 Arguments:
260   HiiDatabase - Point to EFI_HII_DATABASE_PROTOCOL instance.
261   DevicePath  - Device Path associated with the HII package list handle.
262 
263 Returns:
264   Handle - HII package list Handle associated with the Device Path.
265   NULL   - Hii Package list handle is not found.
266 
267 --*/
268 {
269   EFI_STATUS                  Status;
270   EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;
271   UINTN                       BufferSize;
272   UINTN                       HandleCount;
273   UINTN                       Index;
274   EFI_HANDLE                  *Handles;
275   EFI_HANDLE                  Handle;
276   UINTN                       Size;
277   EFI_HANDLE                  DriverHandle;
278   EFI_HII_HANDLE              *HiiHandles;
279   EFI_HII_HANDLE              HiiHandle;
280 
281   //
282   // Locate Device Path Protocol handle buffer
283   //
284   Status = gBS->LocateHandleBuffer (
285                   ByProtocol,
286                   &gEfiDevicePathProtocolGuid,
287                   NULL,
288                   &HandleCount,
289                   &Handles
290                   );
291   if (EFI_ERROR (Status)) {
292     return NULL;
293   }
294 
295   //
296   // Search Driver Handle by Device Path
297   //
298   DriverHandle = NULL;
299   BufferSize = EfiDevicePathSize (DevicePath);
300   for(Index = 0; Index < HandleCount; Index++) {
301     Handle = Handles[Index];
302     gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **) &TmpDevicePath);
303 
304     //
305     // Check whether DevicePath match
306     //
307     Size = EfiDevicePathSize (TmpDevicePath);
308     if ((Size == BufferSize) && EfiCompareMem (DevicePath, TmpDevicePath, Size) == 0) {
309       DriverHandle = Handle;
310       break;
311     }
312   }
313   gBS->FreePool (Handles);
314 
315   if (DriverHandle == NULL) {
316     return NULL;
317   }
318 
319   //
320   // Retrieve all Hii Handles from HII database
321   //
322   BufferSize = 0x1000;
323   HiiHandles = EfiLibAllocatePool (BufferSize);
324   ASSERT (HiiHandles != NULL);
325   Status = HiiDatabase->ListPackageLists (
326                           HiiDatabase,
327                           EFI_HII_PACKAGE_TYPE_ALL,
328                           NULL,
329                           &BufferSize,
330                           HiiHandles
331                           );
332   if (Status == EFI_BUFFER_TOO_SMALL) {
333     gBS->FreePool (HiiHandles);
334     HiiHandles = EfiLibAllocatePool (BufferSize);
335     ASSERT (HiiHandles != NULL);
336 
337     Status = HiiDatabase->ListPackageLists (
338                             HiiDatabase,
339                             EFI_HII_PACKAGE_TYPE_ALL,
340                             NULL,
341                             &BufferSize,
342                             HiiHandles
343                             );
344   }
345 
346   if (EFI_ERROR (Status)) {
347     gBS->FreePool (HiiHandles);
348     return NULL;
349   }
350 
351   //
352   // Search Hii Handle by Driver Handle
353   //
354   HiiHandle = NULL;
355   HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);
356   for (Index = 0; Index < HandleCount; Index++) {
357     Status = HiiDatabase->GetPackageListHandle (
358                             HiiDatabase,
359                             HiiHandles[Index],
360                             &Handle
361                             );
362     if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
363       HiiHandle = HiiHandles[Index];
364       break;
365     }
366   }
367 
368   gBS->FreePool (HiiHandles);
369   return HiiHandle;
370 }
371 
372 EFI_STATUS
GetHiiHandles(IN OUT UINTN * HandleBufferLength,OUT EFI_HII_HANDLE ** HiiHandleBuffer)373 GetHiiHandles (
374   IN OUT UINTN                     *HandleBufferLength,
375   OUT    EFI_HII_HANDLE            **HiiHandleBuffer
376   )
377 /*++
378 
379 Routine Description:
380   Determines the handles that are currently active in the database.
381   It's the caller's responsibility to free handle buffer.
382 
383 Arguments:
384   HiiDatabase           - A pointer to the EFI_HII_DATABASE_PROTOCOL instance.
385   HandleBufferLength    - On input, a pointer to the length of the handle buffer. On output,
386                           the length of the handle buffer that is required for the handles found.
387   HiiHandleBuffer       - Pointer to an array of Hii Handles returned.
388 
389 Returns:
390   EFI_SUCCESS           - Get an array of Hii Handles successfully.
391   EFI_INVALID_PARAMETER - Hii is NULL.
392   EFI_NOT_FOUND         - Database not found.
393 
394 --*/
395 {
396   UINTN       BufferLength;
397   EFI_STATUS  Status;
398 
399   BufferLength = 0;
400 
401   LocateHiiProtocols ();
402 
403   //
404   // Try to find the actual buffer size for HiiHandle Buffer.
405   //
406   Status = gIfrLibHiiDatabase->ListPackageLists (
407                                  gIfrLibHiiDatabase,
408                                  EFI_HII_PACKAGE_TYPE_ALL,
409                                  NULL,
410                                  &BufferLength,
411                                  *HiiHandleBuffer
412                                  );
413 
414   if (Status == EFI_BUFFER_TOO_SMALL) {
415       *HiiHandleBuffer = EfiLibAllocateZeroPool (BufferLength);
416       Status = gIfrLibHiiDatabase->ListPackageLists (
417                                      gIfrLibHiiDatabase,
418                                      EFI_HII_PACKAGE_TYPE_ALL,
419                                      NULL,
420                                      &BufferLength,
421                                      *HiiHandleBuffer
422                                      );
423       //
424       // we should not fail here.
425       //
426       ASSERT_EFI_ERROR (Status);
427   }
428 
429   *HandleBufferLength = BufferLength;
430 
431   return Status;
432 }
433 
434 EFI_STATUS
ExtractGuidFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT EFI_GUID * Guid)435 ExtractGuidFromHiiHandle (
436   IN      EFI_HII_HANDLE      Handle,
437   OUT     EFI_GUID            *Guid
438   )
439 /*++
440 
441 Routine Description:
442   Extract Hii package list GUID for given HII handle.
443 
444 Arguments:
445   HiiHandle     - Hii handle
446   Guid          - Package list GUID
447 
448 Returns:
449   EFI_SUCCESS   - Successfully extract GUID from Hii database.
450 
451 --*/
452 {
453   EFI_STATUS                   Status;
454   UINTN                        BufferSize;
455   EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;
456   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
457 
458   //
459   // Locate HII Database protocol
460   //
461   Status = gBS->LocateProtocol (
462                   &gEfiHiiDatabaseProtocolGuid,
463                   NULL,
464                   (VOID **) &HiiDatabase
465                   );
466   if (EFI_ERROR (Status)) {
467     return Status;
468   }
469 
470   //
471   // Get HII PackageList
472   //
473   BufferSize = 0;
474   HiiPackageList = NULL;
475   Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
476   if (Status == EFI_BUFFER_TOO_SMALL) {
477     HiiPackageList = EfiLibAllocatePool (BufferSize);
478     ASSERT (HiiPackageList != NULL);
479 
480     Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
481   }
482   if (EFI_ERROR (Status)) {
483     return Status;
484   }
485 
486   //
487   // Extract GUID
488   //
489   EfiCopyMem (Guid, &HiiPackageList->PackageListGuid, sizeof (EFI_GUID));
490 
491   gBS->FreePool (HiiPackageList);
492 
493   return EFI_SUCCESS;
494 }
495 
496 EFI_STATUS
ExtractClassFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT UINT16 * Class,OUT EFI_STRING_ID * FormSetTitle,OUT EFI_STRING_ID * FormSetHelp)497 ExtractClassFromHiiHandle (
498   IN      EFI_HII_HANDLE      Handle,
499   OUT     UINT16              *Class,
500   OUT     EFI_STRING_ID       *FormSetTitle,
501   OUT     EFI_STRING_ID       *FormSetHelp
502   )
503 /*++
504 
505 Routine Description:
506   Extract formset class for given HII handle.
507 
508 Arguments:
509   HiiHandle       - Hii handle
510   Class           - Class of the formset
511   FormSetTitle    - Formset title string
512   FormSetHelp     - Formset help string
513 
514 Returns:
515   EFI_SUCCESS     - Successfully extract Class for specified Hii handle.
516   EFI_NOT_FOUND   - Class not found.
517 
518 --*/
519 {
520   EFI_STATUS                   Status;
521   UINTN                        BufferSize;
522   EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;
523   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
524   UINT8                        *Package;
525   UINT8                        *FormSet;
526   UINT8                        *OpCodeData;
527   UINT32                       Offset;
528   UINT32                       Offset2;
529   UINT32                       PackageListLength;
530   EFI_HII_PACKAGE_HEADER       PackageHeader;
531   BOOLEAN                      ClassFound;
532 
533   *Class = EFI_NON_DEVICE_CLASS;
534   *FormSetTitle = 0;
535   *FormSetHelp = 0;
536   ClassFound = FALSE;
537 
538   //
539   // Locate HII Database protocol
540   //
541   Status = gBS->LocateProtocol (
542                   &gEfiHiiDatabaseProtocolGuid,
543                   NULL,
544                   (VOID **) &HiiDatabase
545                   );
546   if (EFI_ERROR (Status)) {
547     return Status;
548   }
549 
550   //
551   // Get HII PackageList
552   //
553   BufferSize = 0;
554   HiiPackageList = NULL;
555   Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
556   if (Status == EFI_BUFFER_TOO_SMALL) {
557     HiiPackageList = EfiLibAllocatePool (BufferSize);
558     ASSERT (HiiPackageList != NULL);
559 
560     Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
561   }
562   if (HiiPackageList == NULL) {
563     return EFI_OUT_OF_RESOURCES;
564   }
565   if (EFI_ERROR (Status)) {
566     gBS->FreePool (HiiPackageList);
567     return Status;
568   }
569 
570   //
571   // Get Form package from this HII package List
572   //
573   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
574   Offset2 = 0;
575   FormSet = NULL;
576   EfiCopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
577 
578   while (Offset < PackageListLength) {
579     Package = ((UINT8 *) HiiPackageList) + Offset;
580     EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
581 
582     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
583       //
584       // Search Class Opcode in this Form Package
585       //
586       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
587       while (Offset2 < PackageHeader.Length) {
588         OpCodeData = Package + Offset2;
589 
590         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
591           //
592           // Find FormSet OpCode
593           //
594           EfiCopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
595           EfiCopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
596         }
597 
598         if ((((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP) &&
599             (EfiCompareGuid (&mIfrVendorGuid, &((EFI_IFR_GUID *) OpCodeData)->Guid)) &&
600             (((EFI_IFR_GUID_CLASS *) OpCodeData)->ExtendOpCode == EFI_IFR_EXTEND_OP_CLASS)
601            ) {
602           //
603           // Find GUIDed Class OpCode
604           //
605           EfiCopyMem (Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16));
606 
607           //
608           // Till now, we ought to have found the formset Opcode
609           //
610           ClassFound = TRUE;
611           break;
612         }
613 
614         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
615       }
616 
617       if (Offset2 < PackageHeader.Length) {
618         //
619         // Target formset found
620         //
621         break;
622       }
623     }
624 
625     Offset += PackageHeader.Length;
626   }
627 
628   gBS->FreePool (HiiPackageList);
629 
630   return ClassFound ? EFI_SUCCESS : EFI_NOT_FOUND;
631 }
632 
633 EFI_STATUS
ExtractClassGuidFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT UINT8 * NumberOfClassGuid,OUT EFI_GUID ** ClassGuid,OUT EFI_STRING_ID * FormSetTitle,OUT EFI_STRING_ID * FormSetHelp)634 ExtractClassGuidFromHiiHandle (
635   IN      EFI_HII_HANDLE      Handle,
636   OUT     UINT8               *NumberOfClassGuid,
637   OUT     EFI_GUID            **ClassGuid,
638   OUT     EFI_STRING_ID       *FormSetTitle,
639   OUT     EFI_STRING_ID       *FormSetHelp
640   )
641 /*++
642 
643 Routine Description:
644   Extract formset ClassGuid for given HII handle.
645 
646 Arguments:
647   HiiHandle         - Hii handle
648   NumberOfClassGuid - Number of ClassGuid
649   ClassGuid         - Pointer to callee allocated buffer, an array of ClassGuid
650   FormSetTitle      - Formset title string
651   FormSetHelp       - Formset help string
652 
653 Returns:
654   EFI_SUCCESS     - Successfully extract Class for specified Hii handle.
655 
656 --*/
657 {
658   EFI_STATUS                   Status;
659   UINTN                        BufferSize;
660   EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;
661   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
662   UINT8                        *Package;
663   UINT8                        *FormSet;
664   UINT8                        *OpCodeData;
665   UINT32                       Offset;
666   UINT32                       Offset2;
667   UINT32                       PackageListLength;
668   EFI_HII_PACKAGE_HEADER       PackageHeader;
669 
670   if (NumberOfClassGuid == NULL || ClassGuid == NULL || FormSetTitle == NULL || FormSetHelp == NULL) {
671     return EFI_INVALID_PARAMETER;
672   }
673 
674   *NumberOfClassGuid = 0;
675   *ClassGuid = NULL;
676   *FormSetTitle = 0;
677   *FormSetHelp = 0;
678 
679   //
680   // Locate HII Database protocol
681   //
682   Status = gBS->LocateProtocol (
683                   &gEfiHiiDatabaseProtocolGuid,
684                   NULL,
685                   (VOID **) &HiiDatabase
686                   );
687   if (EFI_ERROR (Status)) {
688     return Status;
689   }
690 
691   //
692   // Get HII PackageList
693   //
694   BufferSize = 0;
695   HiiPackageList = NULL;
696   Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
697   if (Status == EFI_BUFFER_TOO_SMALL) {
698     HiiPackageList = EfiLibAllocatePool (BufferSize);
699     ASSERT (HiiPackageList != NULL);
700 
701     Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
702   }
703   if (EFI_ERROR (Status) || (HiiPackageList == NULL)) {
704     return Status;
705   }
706 
707   //
708   // Get Form package from this HII package List
709   //
710   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
711   Offset2 = 0;
712   FormSet = NULL;
713   EfiCopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
714 
715   while (Offset < PackageListLength) {
716     Package = ((UINT8 *) HiiPackageList) + Offset;
717     EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
718 
719     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
720       //
721       // Search Class Opcode in this Form Package
722       //
723       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
724       while (Offset2 < PackageHeader.Length) {
725         OpCodeData = Package + Offset2;
726 
727         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
728           //
729           // Find FormSet OpCode
730           //
731           EfiCopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
732           EfiCopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
733           if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > ((UINTN) &((EFI_IFR_FORM_SET *) 0)->Flags)) {
734             //
735             // New version of formset OpCode
736             //
737             *NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
738             *ClassGuid = EfiLibAllocateCopyPool (
739                            *NumberOfClassGuid * sizeof (EFI_GUID),
740                            ((EFI_IFR_FORM_SET *) OpCodeData)->ClassGuid
741                            );
742           }
743           break;
744         }
745 
746         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
747       }
748 
749       if (Offset2 < PackageHeader.Length) {
750         //
751         // Target formset found
752         //
753         break;
754       }
755     }
756 
757     Offset += PackageHeader.Length;
758   }
759 
760   gBS->FreePool (HiiPackageList);
761 
762   return EFI_SUCCESS;
763 }
764