Home | History | Annotate | Download | only in UefiEfiIfrSupportLib
      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
     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 *
     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
    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
    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
    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
    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
    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
    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
    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