]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/HiiLib/HiiLib.c
UEFI HII: Merge UEFI HII support changes from branch.
[mirror_edk2.git] / MdePkg / Library / HiiLib / HiiLib.c
index 6cc5e764e9ec33259da7e9125c9b32577a29a5c5..ef86f5da24832fa54cd3be11a359cd255f0d232a 100644 (file)
 \r
 #include <PiDxe.h>\r
 \r
+#include <Protocol/HiiDatabase.h>\r
+#include <Protocol/HiiString.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
 #include <Library/HiiLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <MdeModuleHii.h>\r
+\r
+#include "InternalHiiLib.h"\r
+\r
+\r
+EFI_HII_DATABASE_PROTOCOL   *mHiiDatabaseProt;\r
+EFI_HII_STRING_PROTOCOL     *mHiiStringProt;\r
+\r
+//\r
+// Hii vendor device path template\r
+//\r
+HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePathTemplate = {\r
+  {\r
+    {\r
+      {\r
+        HARDWARE_DEVICE_PATH,\r
+        HW_VENDOR_DP,\r
+        {\r
+          (UINT8) (sizeof (HII_VENDOR_DEVICE_PATH_NODE)),\r
+          (UINT8) ((sizeof (HII_VENDOR_DEVICE_PATH_NODE)) >> 8)\r
+        }\r
+      },\r
+      EFI_IFR_TIANO_GUID\r
+    },\r
+    0\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    { \r
+      END_DEVICE_PATH_LENGTH\r
+    }\r
+  }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UefiHiiLibConstructor (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  \r
+  Status = gBS->LocateProtocol (\r
+      &gEfiHiiDatabaseProtocolGuid,\r
+      NULL,\r
+      (VOID **) &mHiiDatabaseProt\r
+    );\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT (mHiiDatabaseProt != NULL);\r
+\r
+  Status = gBS->LocateProtocol (\r
+      &gEfiHiiStringProtocolGuid,\r
+      NULL,\r
+      (VOID **) &mHiiStringProt\r
+    );\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT (mHiiStringProt != NULL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+HiiLibGetCurrentLanguage (\r
+  OUT     CHAR8               *Lang\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Determine what is the current language setting\r
+\r
+Arguments:\r
+  Lang      - Pointer of system language\r
+\r
+Returns:\r
+  Status code\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Size;\r
+\r
+  //\r
+  // Get current language setting\r
+  //\r
+  Size = RFC_3066_ENTRY_SIZE;\r
+  Status = gRT->GetVariable (\r
+                  L"PlatformLang",\r
+                  &gEfiGlobalVariableGuid,\r
+                  NULL,\r
+                  &Size,\r
+                  Lang\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    AsciiStrCpy (Lang, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+HiiLibGetNextLanguage (\r
+  IN OUT CHAR8      **LangCode,\r
+  OUT CHAR8         *Lang\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Get next language from language code list (with separator ';').\r
+\r
+Arguments:\r
+  LangCode - On input: point to first language in the list. On output: point to\r
+             next language in the list, or NULL if no more language in the list.\r
+  Lang     - The first language in the list.\r
+\r
+Returns:\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINTN  Index;\r
+  CHAR8  *StringPtr;\r
+\r
+  if (LangCode == NULL || *LangCode == NULL) {\r
+    *Lang = 0;\r
+    return;\r
+  }\r
+\r
+  Index = 0;\r
+  StringPtr = *LangCode;\r
+  while (StringPtr[Index] != 0 && StringPtr[Index] != ';') {\r
+    Index++;\r
+  }\r
+\r
+  CopyMem (Lang, StringPtr, Index);\r
+  Lang[Index] = 0;\r
+\r
+  if (StringPtr[Index] == ';') {\r
+    Index++;\r
+  }\r
+  *LangCode = StringPtr + Index;\r
+}\r
+\r
+CHAR8 *\r
+HiiLibGetSupportedLanguages (\r
+  IN EFI_HII_HANDLE           HiiHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  This function returns the list of supported languages, in the format specified\r
+  in UEFI specification Appendix M.\r
+\r
+Arguments:\r
+  HiiHandle  - The HII package list handle.\r
+\r
+Returns:\r
+  The supported languages.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       BufferSize;\r
+  CHAR8       *LanguageString;\r
+\r
+  //\r
+  // Collect current supported Languages for given HII handle\r
+  //\r
+  BufferSize = 0x1000;\r
+  LanguageString = AllocatePool (BufferSize);\r
+  Status = mHiiStringProt->GetLanguages (mHiiStringProt, HiiHandle, LanguageString, &BufferSize);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    gBS->FreePool (LanguageString);\r
+    LanguageString = AllocatePool (BufferSize);\r
+    Status = mHiiStringProt->GetLanguages (mHiiStringProt, HiiHandle, LanguageString, &BufferSize);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    LanguageString = NULL;\r
+  }\r
+\r
+  return LanguageString;\r
+}\r
+\r
+UINT16\r
+HiiLibGetSupportedLanguageNumber (\r
+  IN EFI_HII_HANDLE           HiiHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  This function returns the number of supported languages\r
+\r
+Arguments:\r
+  HiiHandle  - The HII package list handle.\r
+\r
+Returns:\r
+  The  number of supported languages.\r
+\r
+--*/\r
+{\r
+  CHAR8   *Languages;\r
+  CHAR8   *LanguageString;\r
+  UINT16  LangNumber;\r
+  CHAR8   Lang[RFC_3066_ENTRY_SIZE];\r
+\r
+  Languages = HiiLibGetSupportedLanguages (HiiHandle);\r
+  if (Languages == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  LangNumber = 0;\r
+  LanguageString = Languages;\r
+  while (*LanguageString != 0) {\r
+    HiiLibGetNextLanguage (&LanguageString, Lang);\r
+    LangNumber++;\r
+  }\r
+  gBS->FreePool (Languages);\r
+\r
+  return LangNumber;\r
+}\r
+\r
+\r
+EFI_HII_PACKAGE_LIST_HEADER *\r
+InternalHiiLibPreparePackages (\r
+  IN UINTN           NumberOfPackages,\r
+  IN CONST EFI_GUID  *GuidId, OPTIONAL\r
+  VA_LIST            Marker\r
+  )\r
+{\r
+  EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;\r
+  UINT8                       *PackageListData;\r
+  UINT32                      PackageListLength;\r
+  UINT32                      PackageLength;\r
+  EFI_HII_PACKAGE_HEADER      PackageHeader;\r
+  UINT8                       *PackageArray;\r
+  UINTN                       Index;\r
+  VA_LIST                     MarkerBackup;\r
+\r
+  PackageListLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+\r
+  MarkerBackup = Marker;\r
+  \r
+  for (Index = 0; Index < NumberOfPackages; Index++) {\r
+    CopyMem (&PackageLength, VA_ARG (Marker, VOID *), sizeof (UINT32));\r
+    PackageListLength += (PackageLength - sizeof (UINT32));\r
+  }\r
+\r
+  //\r
+  // Include the lenght of EFI_HII_PACKAGE_END\r
+  //\r
+  PackageListLength += sizeof (EFI_HII_PACKAGE_HEADER);\r
+  PackageListHeader = AllocateZeroPool (PackageListLength);\r
+  ASSERT (PackageListHeader != NULL);\r
+  CopyMem (&PackageListHeader->PackageListGuid, GuidId, sizeof (EFI_GUID));\r
+  PackageListHeader->PackageLength = PackageListLength;\r
+\r
+  PackageListData = ((UINT8 *) PackageListHeader) + sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+\r
+  Marker = MarkerBackup;\r
+  for (Index = 0; Index < NumberOfPackages; Index++) {\r
+    PackageArray = (UINT8 *) VA_ARG (Marker, VOID *);\r
+    CopyMem (&PackageLength, PackageArray, sizeof (UINT32));\r
+    PackageLength  -= sizeof (UINT32);\r
+    PackageArray += sizeof (UINT32);\r
+    CopyMem (PackageListData, PackageArray, PackageLength);\r
+    PackageListData += PackageLength;\r
+  }\r
+\r
+  //\r
+  // Append EFI_HII_PACKAGE_END\r
+  //\r
+  PackageHeader.Type = EFI_HII_PACKAGE_END;\r
+  PackageHeader.Length = sizeof (EFI_HII_PACKAGE_HEADER);\r
+  CopyMem (PackageListData, &PackageHeader, PackageHeader.Length);\r
+\r
+  return PackageListHeader;\r
+}\r
+\r
+EFI_HII_PACKAGE_LIST_HEADER *\r
+EFIAPI\r
+HiiLibPreparePackageList (\r
+  IN UINTN                    NumberOfPackages,\r
+  IN CONST EFI_GUID           *GuidId,\r
+  ...\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Assemble EFI_HII_PACKAGE_LIST according to the passed in packages.\r
+\r
+Arguments:\r
+  NumberOfPackages  -  Number of packages.\r
+  GuidId            -  Package GUID.\r
+\r
+Returns:\r
+  Pointer of EFI_HII_PACKAGE_LIST_HEADER.\r
+\r
+--*/\r
+{\r
+  EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;\r
+  VA_LIST                     Marker;\r
+\r
+  VA_START (Marker, GuidId);\r
+  PackageListHeader = InternalHiiLibPreparePackages (NumberOfPackages, GuidId, Marker);\r
+  VA_END (Marker);\r
+\r
+  return PackageListHeader;\r
+}\r
+\r
 \r
 /**\r
-  This function allocates pool for an EFI_HII_PACKAGES structure\r
-  with enough space for the variable argument list of package pointers.\r
-  The allocated structure is initialized using NumberOfPackages, Guid,\r
-  and the variable length argument list of package pointers.\r
+  This function allocates pool for an EFI_HII_PACKAGE_LIST structure\r
+  with additional space that is big enough to host all packages described by the variable \r
+  argument list of package pointers.  The allocated structure is initialized using NumberOfPackages, \r
+  GuidId,  and the variable length argument list of package pointers.\r
 \r
-  @param  NumberOfPackages The number of HII packages to prepare.\r
-  @param  Guid Package GUID.\r
+  Then, EFI_HII_PACKAGE_LIST will be register to the default System HII Database. The\r
+  Handle to the newly registered Package List is returned throught HiiHandle.\r
 \r
-  @return The allocated and initialized packages.\r
+  @param  NumberOfPackages  The number of HII packages to register.\r
+  @param  GuidId                    Package List GUID ID.\r
+  @param  HiiHandle                The ID used to retrieve the Package List later.\r
+  @param  ...                          The variable argument list describing all HII Package.\r
+\r
+  @return\r
+  The allocated and initialized packages.\r
 \r
 **/\r
-EFI_HII_PACKAGE_LIST_HEADER *\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+HiiLibAddPackagesToHiiDatabase (\r
+  IN       UINTN               NumberOfPackages,\r
+  IN CONST EFI_GUID            *GuidId,\r
+  IN       EFI_HANDLE          DriverHandle, OPTIONAL\r
+  OUT      EFI_HII_HANDLE      *HiiHandle, OPTIONAL\r
+  ...\r
+  )\r
+{\r
+  VA_LIST                   Args;\r
+  EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;\r
+  EFI_STATUS                Status;\r
+\r
+\r
+  VA_START (Args, HiiHandle);\r
+  PackageListHeader = InternalHiiLibPreparePackages (NumberOfPackages, GuidId, Args);\r
+\r
+  Status      = mHiiDatabaseProt->NewPackageList (mHiiDatabaseProt, PackageListHeader, DriverHandle, HiiHandle);\r
+  if (HiiHandle != NULL) {\r
+    if (EFI_ERROR (Status)) {\r
+      *HiiHandle = NULL;\r
+    }\r
+  }\r
+\r
+  FreePool (PackageListHeader);\r
+  VA_END (Args);\r
+  \r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+HiiLibAddFontPackageToHiiDatabase (\r
+  IN       UINTN               FontSize,\r
+  IN CONST UINT8               *FontBinary,\r
+  IN CONST EFI_GUID            *GuidId,\r
+  OUT      EFI_HII_HANDLE      *HiiHandle OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UINT8                                *Location;\r
+  EFI_HII_SIMPLE_FONT_PACKAGE_HDR      *SimplifiedFont;\r
+  UINTN                                PackageLength;\r
+  EFI_HII_PACKAGE_LIST_HEADER          *PackageList;\r
+  UINT8                                *Package;\r
+\r
+  //\r
+  // Add 4 bytes to the header for entire length for PreparePackageList use only.\r
+  // Looks ugly. Might be updated when font tool is ready.\r
+  //\r
+  PackageLength   = sizeof (EFI_HII_SIMPLE_FONT_PACKAGE_HDR) + FontSize + 4;\r
+  Package = AllocateZeroPool (PackageLength);\r
+  if (Package == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  CopyMem (Package, &PackageLength, 4);\r
+  SimplifiedFont = (EFI_HII_SIMPLE_FONT_PACKAGE_HDR*) (Package + 4);\r
+  SimplifiedFont->Header.Length        = (UINT32) (PackageLength - 4);\r
+  SimplifiedFont->Header.Type          = EFI_HII_PACKAGE_SIMPLE_FONTS;\r
+  SimplifiedFont->NumberOfNarrowGlyphs = (UINT16) (FontSize / sizeof (EFI_NARROW_GLYPH));\r
+  \r
+  Location = (UINT8 *) (&SimplifiedFont->NumberOfWideGlyphs + 1);\r
+  CopyMem (Location, FontBinary, FontSize);\r
+  \r
+  //\r
+  // Add this simplified font package to a package list then install it.\r
+  //\r
+  PackageList = HiiLibPreparePackageList (1, GuidId, Package);\r
+  Status = mHiiDatabaseProt->NewPackageList (mHiiDatabaseProt, PackageList, NULL, HiiHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  SafeFreePool (PackageList);\r
+  SafeFreePool (Package);    \r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+HiiLibRemovePackagesFromHiiDatabase (\r
+  IN      EFI_HII_HANDLE      HiiHandle\r
+  )\r
+{\r
+  return mHiiDatabaseProt->RemovePackageList (mHiiDatabaseProt, HiiHandle);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+HiiLibCreateString (\r
+  IN  EFI_HII_HANDLE                  PackageList,\r
+  OUT EFI_STRING_ID                   *StringId,\r
+  IN  CONST EFI_STRING                String\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR8       *Languages;\r
+  CHAR8       *LangStrings;\r
+  CHAR8       Lang[RFC_3066_ENTRY_SIZE];\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  Languages = HiiLibGetSupportedLanguages (PackageList);\r
+\r
+  LangStrings = Languages;\r
+  while (*LangStrings != 0) {\r
+    HiiLibGetNextLanguage (&LangStrings, Lang);\r
+\r
+    Status = mHiiStringProt->NewString (\r
+                                 mHiiStringProt,\r
+                                 PackageList,\r
+                                 StringId,\r
+                                 Lang,\r
+                                 NULL,\r
+                                 String,\r
+                                 NULL\r
+                                 );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (Languages);\r
+\r
+  return Status;\r
+  \r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+HiiLibUpdateString (\r
+  IN  EFI_HII_HANDLE                  PackageList,\r
+  IN  EFI_STRING_ID                   StringId,\r
+  IN  CONST EFI_STRING                String\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR8       *Languages;\r
+  CHAR8       *LangStrings;\r
+  CHAR8       Lang[RFC_3066_ENTRY_SIZE];\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  Languages = HiiLibGetSupportedLanguages (PackageList);\r
+\r
+  LangStrings = Languages;\r
+  while (*LangStrings != 0) {\r
+    HiiLibGetNextLanguage (&LangStrings, Lang);\r
+\r
+    Status = mHiiStringProt->SetString (\r
+                                 mHiiStringProt,\r
+                                 PackageList,\r
+                                 StringId,\r
+                                 Lang,\r
+                                 String,\r
+                                 NULL\r
+                                 );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (Languages);\r
+\r
+  return Status;\r
+}\r
+\r
+//                                                                                      //\r
+// //////////////////////////////////////////////////\r
+//                                                                                    //\r
+\r
+//\r
+// This function is Implementation Specifc. HII_VENDOR_DEVICE_PATH\r
+// This should be moved to MdeModulepkg.\r
+//\r
+EFI_STATUS\r
 EFIAPI\r
-PreparePackages (\r
-  IN CONST  UINTN     NumberOfPackages,\r
-  IN CONST  EFI_GUID  *Guid OPTIONAL,\r
+HiiLibCreateHiiDriverHandle (\r
+  OUT EFI_HANDLE               *DriverHandle\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  HII_VENDOR_DEVICE_PATH_NODE  *VendorDevicePath;\r
+  UINT64                       MonotonicCount;\r
+\r
+  VendorDevicePath = AllocateCopyPool (sizeof (HII_VENDOR_DEVICE_PATH), &mHiiVendorDevicePathTemplate);\r
+  if (VendorDevicePath == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  gBS->GetNextMonotonicCount (&MonotonicCount);\r
+  VendorDevicePath->MonotonicCount = (UINT32) MonotonicCount;\r
+\r
+  *DriverHandle = NULL;\r
+  Status = gBS->InstallProtocolInterface (\r
+                  DriverHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  VendorDevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+HiiLibDestroyHiiDriverHandle (\r
+  IN EFI_HANDLE               DriverHandle\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_DEVICE_PATH_PROTOCOL     *DevicePath;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  DriverHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &DevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  DriverHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  DevicePath\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+HiiLibExtractDefault(\r
+  IN VOID                         *Buffer,\r
+  IN UINTN                        *BufferSize,\r
+  UINTN                           Number,\r
   ...\r
   )\r
+/*++\r
+\r
+  Routine Description:\r
+\r
+    Configure the buffer accrording to ConfigBody strings.\r
+\r
+  Arguments:\r
+    DefaultId             - the ID of default.\r
+    Buffer                - the start address of buffer.\r
+    BufferSize            - the size of buffer.\r
+    Number                - the number of the strings.\r
+\r
+  Returns:\r
+    EFI_BUFFER_TOO_SMALL  - the BufferSize is too small to operate.\r
+    EFI_INVALID_PARAMETER - Buffer is NULL or BufferSize is 0.\r
+    EFI_SUCCESS           - Operation successful.\r
+\r
+--*/\r
 {\r
+  VA_LIST                         Args;\r
+  UINTN                           Index;\r
+  UINT32                          TotalLen;\r
+  UINT8                           *BufCfgArray;\r
+  UINT8                           *BufferPos;\r
+  UINT16                          Offset;\r
+  UINT16                          Width;\r
+  UINT8                           *Value;\r
+\r
+  if ((Buffer == NULL) || (BufferSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Offset = 0;\r
+  Width  = 0;\r
+  Value  = NULL;\r
+\r
+  VA_START (Args, Number);\r
+  for (Index = 0; Index < Number; Index++) {\r
+    BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);\r
+    CopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));\r
+    BufferPos = BufCfgArray + sizeof (UINT32);\r
+\r
+    while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {\r
+      CopyMem (&Offset, BufferPos, sizeof (UINT16));\r
+      BufferPos += sizeof (UINT16);\r
+      CopyMem (&Width, BufferPos, sizeof (UINT16));\r
+      BufferPos += sizeof (UINT16);\r
+      Value = BufferPos;\r
+      BufferPos += Width;\r
+\r
+      if ((UINTN)(Offset + Width) > *BufferSize) {\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+\r
+      CopyMem ((UINT8 *)Buffer + Offset, Value, Width);\r
+    }\r
+  }\r
+  VA_END (Args);\r
+\r
+  *BufferSize = (UINTN)Offset;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+STATIC EFI_GUID mIfrVendorGuid = EFI_IFR_TIANO_GUID;\r
+\r
+EFI_STATUS\r
+HiiLibExtractClassFromHiiHandle (\r
+  IN      EFI_HII_HANDLE      Handle,\r
+  OUT     UINT16              *Class,\r
+  OUT     EFI_STRING_ID       *FormSetTitle,\r
+  OUT     EFI_STRING_ID       *FormSetHelp\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Extract formset class for given HII handle.\r
+\r
+Arguments:\r
+  HiiHandle       - Hii handle\r
+  Class           - Class of the formset\r
+  FormSetTitle    - Formset title string\r
+  FormSetHelp     - Formset help string\r
+\r
+Returns:\r
+  EFI_SUCCESS     - Successfully extract Class for specified Hii handle.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINTN                        BufferSize;\r
+  EFI_HII_DATABASE_PROTOCOL    *HiiDatabase;\r
+  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
+  UINT8                        *Package;\r
+  UINT8                        *OpCodeData;\r
+  UINT32                       Offset;\r
+  UINT32                       Offset2;\r
+  UINT32                       PackageListLength;\r
+  EFI_HII_PACKAGE_HEADER       PackageHeader;\r
+\r
+  *Class = EFI_NON_DEVICE_CLASS;\r
+  *FormSetTitle = 0;\r
+  *FormSetHelp = 0;\r
+\r
   //\r
-  // BugBug: Need more detail on UEFI spec.\r
+  // Locate HII Database protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiHiiDatabaseProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &HiiDatabase\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get HII PackageList\r
+  //\r
+  BufferSize = 0;\r
+  HiiPackageList = NULL;\r
+  Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    HiiPackageList = AllocatePool (BufferSize);\r
+    ASSERT (HiiPackageList != NULL);\r
+\r
+    Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   //\r
-  ASSERT (FALSE);\r
-  return NULL;\r
+  // Get Form package from this HII package List\r
+  //\r
+  Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+  Offset2 = 0;\r
+  CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));\r
+\r
+  while (Offset < PackageListLength) {\r
+    Package = ((UINT8 *) HiiPackageList) + Offset;\r
+    CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+    if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) {\r
+      //\r
+      // Search Class Opcode in this Form Package\r
+      //\r
+      Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+      while (Offset2 < PackageHeader.Length) {\r
+        OpCodeData = Package + Offset2;\r
+\r
+        if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+          //\r
+          // Find FormSet OpCode\r
+          //\r
+          CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));\r
+          CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));\r
+        }\r
+\r
+        if ((((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP) &&\r
+             CompareGuid (&mIfrVendorGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER))) &&\r
+            (((EFI_IFR_GUID_CLASS *) OpCodeData)->ExtendOpCode == EFI_IFR_EXTEND_OP_CLASS)\r
+           ) {\r
+          //\r
+          // Find GUIDed Class OpCode\r
+          //\r
+          CopyMem (Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16));\r
+\r
+          //\r
+          // Till now, we ought to have found the formset Opcode\r
+          //\r
+          break;\r
+        }\r
+\r
+        Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+      }\r
+\r
+      if (Offset2 < PackageHeader.Length) {\r
+        //\r
+        // Target formset found\r
+        //\r
+        break;\r
+      }\r
+    }\r
+\r
+    Offset += PackageHeader.Length;\r
+  }\r
+\r
+  gBS->FreePool (HiiPackageList);\r
+\r
+  return EFI_SUCCESS;\r
 }\r
+\r