• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                        *OpCodeData;
526   UINT32                       Offset;
527   UINT32                       Offset2;
528   UINT32                       PackageListLength;
529   EFI_HII_PACKAGE_HEADER       PackageHeader;
530   BOOLEAN                      ClassFound;
531 
532   *Class = EFI_NON_DEVICE_CLASS;
533   *FormSetTitle = 0;
534   *FormSetHelp = 0;
535   ClassFound = FALSE;
536 
537   //
538   // Locate HII Database protocol
539   //
540   Status = gBS->LocateProtocol (
541                   &gEfiHiiDatabaseProtocolGuid,
542                   NULL,
543                   (VOID **) &HiiDatabase
544                   );
545   if (EFI_ERROR (Status)) {
546     return Status;
547   }
548 
549   //
550   // Get HII PackageList
551   //
552   BufferSize = 0;
553   HiiPackageList = NULL;
554   Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
555   if (Status == EFI_BUFFER_TOO_SMALL) {
556     HiiPackageList = EfiLibAllocatePool (BufferSize);
557     ASSERT (HiiPackageList != NULL);
558 
559     Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
560   }
561   if (HiiPackageList == NULL) {
562     return EFI_OUT_OF_RESOURCES;
563   }
564   if (EFI_ERROR (Status)) {
565     gBS->FreePool (HiiPackageList);
566     return Status;
567   }
568 
569   //
570   // Get Form package from this HII package List
571   //
572   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
573   Offset2 = 0;
574   EfiCopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
575 
576   while (Offset < PackageListLength) {
577     Package = ((UINT8 *) HiiPackageList) + Offset;
578     EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
579 
580     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
581       //
582       // Search Class Opcode in this Form Package
583       //
584       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
585       while (Offset2 < PackageHeader.Length) {
586         OpCodeData = Package + Offset2;
587 
588         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
589           //
590           // Find FormSet OpCode
591           //
592           EfiCopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
593           EfiCopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
594         }
595 
596         if ((((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP) &&
597             (EfiCompareGuid (&mIfrVendorGuid, &((EFI_IFR_GUID *) OpCodeData)->Guid)) &&
598             (((EFI_IFR_GUID_CLASS *) OpCodeData)->ExtendOpCode == EFI_IFR_EXTEND_OP_CLASS)
599            ) {
600           //
601           // Find GUIDed Class OpCode
602           //
603           EfiCopyMem (Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16));
604 
605           //
606           // Till now, we ought to have found the formset Opcode
607           //
608           ClassFound = TRUE;
609           break;
610         }
611 
612         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
613       }
614 
615       if (Offset2 < PackageHeader.Length) {
616         //
617         // Target formset found
618         //
619         break;
620       }
621     }
622 
623     Offset += PackageHeader.Length;
624   }
625 
626   gBS->FreePool (HiiPackageList);
627 
628   return ClassFound ? EFI_SUCCESS : EFI_NOT_FOUND;
629 }
630 
631 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)632 ExtractClassGuidFromHiiHandle (
633   IN      EFI_HII_HANDLE      Handle,
634   OUT     UINT8               *NumberOfClassGuid,
635   OUT     EFI_GUID            **ClassGuid,
636   OUT     EFI_STRING_ID       *FormSetTitle,
637   OUT     EFI_STRING_ID       *FormSetHelp
638   )
639 /*++
640 
641 Routine Description:
642   Extract formset ClassGuid for given HII handle.
643 
644 Arguments:
645   HiiHandle         - Hii handle
646   NumberOfClassGuid - Number of ClassGuid
647   ClassGuid         - Pointer to callee allocated buffer, an array of ClassGuid
648   FormSetTitle      - Formset title string
649   FormSetHelp       - Formset help string
650 
651 Returns:
652   EFI_SUCCESS     - Successfully extract Class for specified Hii handle.
653 
654 --*/
655 {
656   EFI_STATUS                   Status;
657   UINTN                        BufferSize;
658   EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;
659   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
660   UINT8                        *Package;
661   UINT8                        *OpCodeData;
662   UINT32                       Offset;
663   UINT32                       Offset2;
664   UINT32                       PackageListLength;
665   EFI_HII_PACKAGE_HEADER       PackageHeader;
666 
667   if (NumberOfClassGuid == NULL || ClassGuid == NULL || FormSetTitle == NULL || FormSetHelp == NULL) {
668     return EFI_INVALID_PARAMETER;
669   }
670 
671   *NumberOfClassGuid = 0;
672   *ClassGuid = NULL;
673   *FormSetTitle = 0;
674   *FormSetHelp = 0;
675 
676   //
677   // Locate HII Database protocol
678   //
679   Status = gBS->LocateProtocol (
680                   &gEfiHiiDatabaseProtocolGuid,
681                   NULL,
682                   (VOID **) &HiiDatabase
683                   );
684   if (EFI_ERROR (Status)) {
685     return Status;
686   }
687 
688   //
689   // Get HII PackageList
690   //
691   BufferSize = 0;
692   HiiPackageList = NULL;
693   Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
694   if (Status == EFI_BUFFER_TOO_SMALL) {
695     HiiPackageList = EfiLibAllocatePool (BufferSize);
696     ASSERT (HiiPackageList != NULL);
697 
698     Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
699   }
700   if (EFI_ERROR (Status) || (HiiPackageList == NULL)) {
701     return Status;
702   }
703 
704   //
705   // Get Form package from this HII package List
706   //
707   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
708   Offset2 = 0;
709   EfiCopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
710 
711   while (Offset < PackageListLength) {
712     Package = ((UINT8 *) HiiPackageList) + Offset;
713     EfiCopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
714 
715     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
716       //
717       // Search Class Opcode in this Form Package
718       //
719       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
720       while (Offset2 < PackageHeader.Length) {
721         OpCodeData = Package + Offset2;
722 
723         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
724           //
725           // Find FormSet OpCode
726           //
727           EfiCopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
728           EfiCopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
729           if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > ((UINTN) &((EFI_IFR_FORM_SET *) 0)->Flags)) {
730             //
731             // New version of formset OpCode
732             //
733             *NumberOfClassGuid = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
734             *ClassGuid = EfiLibAllocateCopyPool (
735                            *NumberOfClassGuid * sizeof (EFI_GUID),
736                            ((EFI_IFR_FORM_SET *) OpCodeData)->ClassGuid
737                            );
738           }
739           break;
740         }
741 
742         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
743       }
744 
745       if (Offset2 < PackageHeader.Length) {
746         //
747         // Target formset found
748         //
749         break;
750       }
751     }
752 
753     Offset += PackageHeader.Length;
754   }
755 
756   gBS->FreePool (HiiPackageList);
757 
758   return EFI_SUCCESS;
759 }
760