--- /dev/null
+/*++\r
+\r
+Copyright (c) 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+ UefiIfrCommon.c\r
+\r
+Abstract:\r
+\r
+ Common Library Routines to assist handle HII elements.\r
+\r
+--*/\r
+\r
+#include "UefiIfrLibrary.h"\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
+ (UINT8) (sizeof (HII_VENDOR_DEVICE_PATH_NODE)),\r
+ (UINT8) ((sizeof (HII_VENDOR_DEVICE_PATH_NODE)) >> 8)\r
+ },\r
+ EFI_IFR_TIANO_GUID,\r
+ },\r
+ 0\r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ END_DEVICE_PATH_LENGTH,\r
+ 0\r
+ }\r
+};\r
+\r
+//\r
+// Hii relative protocols\r
+//\r
+BOOLEAN mHiiProtocolsInitialized = FALSE;\r
+\r
+EFI_HII_DATABASE_PROTOCOL *gIfrLibHiiDatabase;\r
+EFI_HII_STRING_PROTOCOL *gIfrLibHiiString;\r
+\r
+VOID\r
+LocateHiiProtocols (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ This function locate Hii relative protocols for later usage.\r
+\r
+Arguments:\r
+ None.\r
+\r
+Returns:\r
+ None.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (mHiiProtocolsInitialized) {\r
+ return;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, &gIfrLibHiiDatabase);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, &gIfrLibHiiString);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ mHiiProtocolsInitialized = TRUE;\r
+}\r
+\r
+EFI_HII_PACKAGE_LIST_HEADER *\r
+PreparePackageList (\r
+ IN UINTN NumberOfPackages,\r
+ IN 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
+ VA_LIST Marker;\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
+\r
+ PackageListLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+\r
+ VA_START (Marker, GuidId);\r
+ for (Index = 0; Index < NumberOfPackages; Index++) {\r
+ EfiCopyMem (&PackageLength, VA_ARG (Marker, VOID *), sizeof (UINT32));\r
+ PackageListLength += (PackageLength - sizeof (UINT32));\r
+ }\r
+ VA_END (Marker);\r
+\r
+ //\r
+ // Include the lenght of EFI_HII_PACKAGE_END\r
+ //\r
+ PackageListLength += sizeof (EFI_HII_PACKAGE_HEADER);\r
+ PackageListHeader = EfiLibAllocateZeroPool (PackageListLength);\r
+ ASSERT (PackageListHeader != NULL);\r
+ EfiCopyMem (&PackageListHeader->PackageListGuid, GuidId, sizeof (EFI_GUID));\r
+ PackageListHeader->PackageLength = PackageListLength;\r
+\r
+ PackageListData = ((UINT8 *) PackageListHeader) + sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+\r
+ VA_START (Marker, GuidId);\r
+ for (Index = 0; Index < NumberOfPackages; Index++) {\r
+ PackageArray = (UINT8 *) VA_ARG (Marker, VOID *);\r
+ EfiCopyMem (&PackageLength, PackageArray, sizeof (UINT32));\r
+ PackageLength -= sizeof (UINT32);\r
+ PackageArray += sizeof (UINT32);\r
+ EfiCopyMem (PackageListData, PackageArray, PackageLength);\r
+ PackageListData += PackageLength;\r
+ }\r
+ VA_END (Marker);\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
+ EfiCopyMem (PackageListData, &PackageHeader, PackageHeader.Length);\r
+\r
+ return PackageListHeader;\r
+}\r
+\r
+EFI_STATUS\r
+CreateHiiDriverHandle (\r
+ OUT EFI_HANDLE *DriverHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ The HII driver handle passed in for HiiDatabase.NewPackageList() requires\r
+ that there should be DevicePath Protocol installed on it.\r
+ This routine create a virtual Driver Handle by installing a vendor device\r
+ path on it, so as to use it to invoke HiiDatabase.NewPackageList().\r
+\r
+Arguments:\r
+ DriverHandle - Handle to be returned\r
+\r
+Returns:\r
+ EFI_SUCCESS - Handle destroy success.\r
+ EFI_OUT_OF_RESOURCES - Not enough memory.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ HII_VENDOR_DEVICE_PATH_NODE *VendorDevicePath;\r
+ UINT64 MonotonicCount;\r
+\r
+ VendorDevicePath = EfiLibAllocateCopyPool (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
+EFI_STATUS\r
+DestroyHiiDriverHandle (\r
+ IN EFI_HANDLE DriverHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Destroy the Driver Handle created by CreateHiiDriverHandle().\r
+\r
+Arguments:\r
+ DriverHandle - Handle returned by CreateHiiDriverHandle()\r
+\r
+Returns:\r
+ EFI_SUCCESS - Handle destroy success.\r
+ other - Handle destroy fail.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &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_HII_HANDLE\r
+DevicePathToHiiHandle (\r
+ IN EFI_HII_DATABASE_PROTOCOL *HiiDatabase,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Find HII Handle associated with given Device Path.\r
+\r
+Arguments:\r
+ HiiDatabase - Point to EFI_HII_DATABASE_PROTOCOL instance.\r
+ DevicePath - Device Path associated with the HII package list handle.\r
+\r
+Returns:\r
+ Handle - HII package list Handle associated with the Device Path.\r
+ NULL - Hii Package list handle is not found.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
+ UINTN BufferSize;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_HANDLE *Handles;\r
+ EFI_HANDLE Handle;\r
+ UINTN Size;\r
+ EFI_HANDLE DriverHandle;\r
+ EFI_HII_HANDLE *HiiHandles;\r
+ EFI_HII_HANDLE HiiHandle;\r
+\r
+ //\r
+ // Locate Device Path Protocol handle buffer\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiDevicePathProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Search Driver Handle by Device Path\r
+ //\r
+ DriverHandle = NULL;\r
+ BufferSize = EfiDevicePathSize (DevicePath);\r
+ for(Index = 0; Index < HandleCount; Index++) {\r
+ Handle = Handles[Index];\r
+ gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, &TmpDevicePath);\r
+\r
+ //\r
+ // Check whether DevicePath match\r
+ //\r
+ Size = EfiDevicePathSize (TmpDevicePath);\r
+ if ((Size == BufferSize) && EfiCompareMem (DevicePath, TmpDevicePath, Size) == 0) {\r
+ DriverHandle = Handle;\r
+ break;\r
+ }\r
+ }\r
+ gBS->FreePool (Handles);\r
+\r
+ if (DriverHandle == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Retrieve all Hii Handles from HII database\r
+ //\r
+ BufferSize = 0x1000;\r
+ HiiHandles = EfiLibAllocatePool (BufferSize);\r
+ ASSERT (HiiHandles != NULL);\r
+ Status = HiiDatabase->ListPackageLists (\r
+ HiiDatabase,\r
+ EFI_HII_PACKAGE_TYPE_ALL,\r
+ NULL,\r
+ &BufferSize,\r
+ HiiHandles\r
+ );\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ gBS->FreePool (HiiHandles);\r
+ HiiHandles = EfiLibAllocatePool (BufferSize);\r
+ ASSERT (HiiHandles != NULL);\r
+\r
+ Status = HiiDatabase->ListPackageLists (\r
+ HiiDatabase,\r
+ EFI_HII_PACKAGE_TYPE_ALL,\r
+ NULL,\r
+ &BufferSize,\r
+ HiiHandles\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (HiiHandles);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Search Hii Handle by Driver Handle\r
+ //\r
+ HiiHandle = NULL;\r
+ HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = HiiDatabase->GetPackageListHandle (\r
+ HiiDatabase,\r
+ HiiHandles[Index],\r
+ &Handle\r
+ );\r
+ if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
+ HiiHandle = HiiHandles[Index];\r
+ break;\r
+ }\r
+ }\r
+\r
+ gBS->FreePool (HiiHandles);\r
+ return HiiHandle;\r
+}\r
+\r
+EFI_STATUS\r
+GetHiiHandles (\r
+ IN OUT UINTN *HandleBufferLength,\r
+ OUT EFI_HII_HANDLE **HiiHandleBuffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Determines the handles that are currently active in the database.\r
+ It's the caller's responsibility to free handle buffer.\r
+\r
+Arguments:\r
+ HiiDatabase - A pointer to the EFI_HII_DATABASE_PROTOCOL instance.\r
+ HandleBufferLength - On input, a pointer to the length of the handle buffer. On output,\r
+ the length of the handle buffer that is required for the handles found.\r
+ HiiHandleBuffer - Pointer to an array of Hii Handles returned.\r
+\r
+Returns:\r
+ EFI_SUCCESS - Get an array of Hii Handles successfully.\r
+ EFI_INVALID_PARAMETER - Hii is NULL.\r
+ EFI_NOT_FOUND - Database not found.\r
+\r
+--*/\r
+{\r
+ UINTN BufferLength;\r
+ EFI_STATUS Status;\r
+\r
+ BufferLength = 0;\r
+\r
+ LocateHiiProtocols ();\r
+\r
+ //\r
+ // Try to find the actual buffer size for HiiHandle Buffer.\r
+ //\r
+ Status = gIfrLibHiiDatabase->ListPackageLists (\r
+ gIfrLibHiiDatabase,\r
+ EFI_HII_PACKAGE_TYPE_ALL,\r
+ NULL,\r
+ &BufferLength,\r
+ *HiiHandleBuffer\r
+ );\r
+\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ *HiiHandleBuffer = EfiLibAllocateZeroPool (BufferLength);\r
+ Status = gIfrLibHiiDatabase->ListPackageLists (\r
+ gIfrLibHiiDatabase,\r
+ EFI_HII_PACKAGE_TYPE_ALL,\r
+ NULL,\r
+ &BufferLength,\r
+ *HiiHandleBuffer\r
+ );\r
+ //\r
+ // we should not fail here.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ *HandleBufferLength = BufferLength;\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+ExtractGuidFromHiiHandle (\r
+ IN EFI_HII_HANDLE Handle,\r
+ OUT EFI_GUID *Guid\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Extract Hii package list GUID for given HII handle.\r
+\r
+Arguments:\r
+ HiiHandle - Hii handle\r
+ Guid - Package list GUID\r
+\r
+Returns:\r
+ EFI_SUCCESS - Successfully extract GUID from Hii database.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;\r
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
+\r
+ //\r
+ // Locate HII Database protocol\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiDatabaseProtocolGuid,\r
+ NULL,\r
+ &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 = EfiLibAllocatePool (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
+ // Extract GUID\r
+ //\r
+ EfiCopyMem (Guid, &HiiPackageList->PackageListGuid, sizeof (EFI_GUID));\r
+\r
+ gBS->FreePool (HiiPackageList);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+ExtractClassFromHiiHandle (\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 *FormSet;\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
+ // Locate HII Database protocol\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiDatabaseProtocolGuid,\r
+ NULL,\r
+ &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 = EfiLibAllocatePool (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
+ // Get Form package from this HII package List\r
+ //\r
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+ Offset2 = 0;\r
+ FormSet = NULL;\r
+ EfiCopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));\r
+\r
+ while (Offset < PackageListLength) {\r
+ Package = ((UINT8 *) HiiPackageList) + Offset;\r
+ EfiCopyMem (&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
+ EfiCopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));\r
+ EfiCopyMem (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
+ (EfiCompareGuid (&mIfrVendorGuid, &((EFI_IFR_GUID *) OpCodeData)->Guid)) &&\r
+ (((EFI_IFR_GUID_CLASS *) OpCodeData)->ExtendOpCode == EFI_IFR_EXTEND_OP_CLASS)\r
+ ) {\r
+ //\r
+ // Find GUIDed Class OpCode\r
+ //\r
+ EfiCopyMem (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