X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FLibrary%2FUefiHiiLib%2FHiiLib.c;h=df73b7b3a19359b5f13f380b9e10b57750bb0473;hb=8567300ae4047da0891d62eedf50d407a23c5203;hp=83e33d2a6ee67b7501df037fe0a83ab93dba2a27;hpb=fa7b3168fdfc8744f658a5ba5c4e433fc0ae7c82;p=mirror_edk2.git diff --git a/MdeModulePkg/Library/UefiHiiLib/HiiLib.c b/MdeModulePkg/Library/UefiHiiLib/HiiLib.c index 83e33d2a6e..df73b7b3a1 100644 --- a/MdeModulePkg/Library/UefiHiiLib/HiiLib.c +++ b/MdeModulePkg/Library/UefiHiiLib/HiiLib.c @@ -14,48 +14,104 @@ #include "InternalHiiLib.h" -CONST EFI_HII_DATABASE_PROTOCOL *mHiiDatabaseProt = NULL; -CONST EFI_HII_STRING_PROTOCOL *mHiiStringProt = NULL; +#define GUID_CONFIG_STRING_TYPE 0x00 +#define NAME_CONFIG_STRING_TYPE 0x01 +#define PATH_CONFIG_STRING_TYPE 0x02 + +#define ACTION_SET_DEFAUTL_VALUE 0x01 +#define ACTION_VALIDATE_SETTING 0x02 + +#define HII_LIB_DEFAULT_VARSTORE_SIZE 0x200 + +typedef struct { + LIST_ENTRY Entry; // Link to Block array + UINT16 Offset; + UINT16 Width; + UINT8 OpCode; + UINT8 Scope; +} IFR_BLOCK_DATA; + +// +// Template +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR16 mConfigHdrTemplate[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=00"; + +EFI_FORM_BROWSER2_PROTOCOL *mUefiFormBrowser2 = NULL; + +// +// Template used to mark the end of a list of packages +// +GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_HII_PACKAGE_HEADER mEndOfPakageList = { + sizeof (EFI_HII_PACKAGE_HEADER), + EFI_HII_PACKAGE_END +}; /** - This function locate Hii relative protocols for later usage. - - The constructor function caches the protocol pointer of HII Database Protocol - and Hii String Protocol. - - It will ASSERT() if either of the protocol can't be located. + Extract Hii package list GUID for given HII handle. + + If HiiHandle could not be found in the HII database, then ASSERT. + If Guid is NULL, then ASSERT. - @param ImageHandle The firmware allocated handle for the EFI image. - @param SystemTable A pointer to the EFI System Table. + @param Handle Hii handle + @param Guid Package list GUID - @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + @retval EFI_SUCCESS Successfully extract GUID from Hii database. **/ EFI_STATUS EFIAPI -HiiLibConstructor ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable +InternalHiiExtractGuidFromHiiHandle ( + IN EFI_HII_HANDLE Handle, + OUT EFI_GUID *Guid ) { - EFI_STATUS Status; + EFI_STATUS Status; + UINTN BufferSize; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; - Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &mHiiDatabaseProt); - ASSERT_EFI_ERROR (Status); + ASSERT (Guid != NULL); + ASSERT (Handle != NULL); - Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &mHiiStringProt); - ASSERT_EFI_ERROR (Status); + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; - return EFI_SUCCESS; -} + Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList); + ASSERT (Status != EFI_NOT_FOUND); + + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status)) { + FreePool (HiiPackageList); + return Status; + } + + // + // Extract GUID + // + CopyGuid (Guid, &HiiPackageList->PackageListGuid); + FreePool (HiiPackageList); + return EFI_SUCCESS; +} /** - This funciton build the package list based on the package number, - the GUID of the package list and the list of pointer which point to - package header that defined by UEFI VFR compiler and StringGather - tool. + Registers a list of packages in the HII Database and returns the HII Handle + associated with that registration. If an HII Handle has already been registered + with the same PackageListGuid, then NULL is returned. If there are not enough + resources to perform the registration, then NULL is returned. If an empty list + of packages is passed in, then NULL is returned. If the size of the list of + package is 0, then NULL is returned. + + The variable arguments are pointers which point to package header that defined + by UEFI VFR compiler and StringGather tool. #pragma pack (push, 1) typedef struct { @@ -63,635 +119,3490 @@ HiiLibConstructor ( EFI_HII_PACKAGE_HEADER PackageHeader; } EDKII_AUTOGEN_PACKAGES_HEADER; #pragma pack (pop) - - If there is not enough resource for the new package list, - the function will ASSERT. - - @param NumberOfPackages The number of packages be - @param GuidId The GUID for the package list to be generated. - @param Marker The variable argument list. Each entry represent a specific package header that is - generated by VFR compiler and StrGather tool. The first 4 bytes is a UINT32 value - that indicate the overall length of the package. - - @return The pointer to the package list header. + + @param[in] PackageListGuid The GUID of the package list. + @param[in] DeviceHandle If not NULL, the Device Handle on which + an instance of DEVICE_PATH_PROTOCOL is installed. + This Device Handle uniquely defines the device that + the added packages are associated with. + @param[in] ... The variable argument list that contains pointers + to packages terminated by a NULL. + + @retval NULL A HII Handle has already been registered in the HII Database with + the same PackageListGuid. + @retval NULL The HII Handle could not be created. + @retval NULL An empty list of packages was passed in. + @retval NULL All packages are empty. + @retval Other The HII Handle associated with the newly registered package list. **/ -EFI_HII_PACKAGE_LIST_HEADER * -InternalHiiLibPreparePackages ( - IN UINTN NumberOfPackages, - IN CONST EFI_GUID *GuidId, - IN VA_LIST Marker +EFI_HII_HANDLE +EFIAPI +HiiAddPackages ( + IN CONST EFI_GUID *PackageListGuid, + IN EFI_HANDLE DeviceHandle OPTIONAL, + ... ) { - EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; - UINT8 *PackageListData; - UINT32 PackageListLength; - UINT32 PackageLength; - EFI_HII_PACKAGE_HEADER PackageHeader; - UINT8 *PackageArray; - UINTN Index; - VA_LIST MarkerBackup; - - PackageListLength = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + EFI_STATUS Status; + EFI_HII_HANDLE *HiiHandleBuffer; + VA_LIST Args; + UINT32 *Package; + EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; + EFI_HII_HANDLE HiiHandle; + UINT32 Length; + UINT8 *Data; - MarkerBackup = Marker; + ASSERT (PackageListGuid != NULL); // - // Count the length of the final package list. + // Check to see if an HII Handle has already been registered with the same + // PackageListGuid // - for (Index = 0; Index < NumberOfPackages; Index++) { - CopyMem (&PackageLength, VA_ARG (Marker, VOID *), sizeof (UINT32)); - // - // Do not count the BinaryLength field. - // - PackageListLength += (PackageLength - sizeof (UINT32)); + HiiHandleBuffer = HiiGetHiiHandles (PackageListGuid); + if (HiiHandleBuffer != NULL) { + FreePool (HiiHandleBuffer); + return NULL; } // - // Include the length of EFI_HII_PACKAGE_END + // Calculate the length of all the packages in the variable argument list // - PackageListLength += sizeof (EFI_HII_PACKAGE_HEADER); - PackageListHeader = AllocateZeroPool (PackageListLength); - ASSERT (PackageListHeader != NULL); - - CopyGuid (&PackageListHeader->PackageListGuid, GuidId); - PackageListHeader->PackageLength = PackageListLength; - - PackageListData = ((UINT8 *) PackageListHeader) + sizeof (EFI_HII_PACKAGE_LIST_HEADER); + for (Length = 0, VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) { + Length += (ReadUnaligned32 (Package) - sizeof (UINT32)); + } + VA_END (Args); - Marker = MarkerBackup; // - // Prepare the final package list. + // If there are no packages in the variable argument list or all the packages + // are empty, then return a NULL HII Handle // - for (Index = 0; Index < NumberOfPackages; Index++) { - PackageArray = (UINT8 *) VA_ARG (Marker, VOID *); - // - // CopyMem is used for UINT32 to cover the unaligned address access. - // - CopyMem (&PackageLength, PackageArray, sizeof (UINT32)); - PackageLength -= sizeof (UINT32); - PackageArray += sizeof (UINT32); - CopyMem (PackageListData, PackageArray, PackageLength); - PackageListData += PackageLength; + if (Length == 0) { + return NULL; } // - // Append EFI_HII_PACKAGE_END + // Add the length of the Package List Header and the terminating Package Header // - PackageHeader.Type = EFI_HII_PACKAGE_END; - PackageHeader.Length = sizeof (EFI_HII_PACKAGE_HEADER); - CopyMem (PackageListData, &PackageHeader, PackageHeader.Length); - - return PackageListHeader; -} + Length += sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EFI_HII_PACKAGE_HEADER); -/** - Assemble EFI_HII_PACKAGE_LIST according to the passed in packages. - - If GuidId is NULL, then ASSERT. - If not enough resource to complete the operation, then ASSERT. - - @param NumberOfPackages Number of packages. - @param GuidId Package GUID. - @param ... Variable argument list for packages to be assembled. - - @return Pointer of EFI_HII_PACKAGE_LIST_HEADER. - -**/ -EFI_HII_PACKAGE_LIST_HEADER * -EFIAPI -HiiLibPreparePackageList ( - IN UINTN NumberOfPackages, - IN CONST EFI_GUID *GuidId, - ... - ) -{ - EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; - VA_LIST Marker; - - ASSERT (GuidId != NULL); - - VA_START (Marker, GuidId); - PackageListHeader = InternalHiiLibPreparePackages (NumberOfPackages, GuidId, Marker); - VA_END (Marker); - - return PackageListHeader; -} - - -/** - This function allocates pool for an EFI_HII_PACKAGE_LIST structure - with additional space that is big enough to host all packages described by the variable - argument list of package pointers. The allocated structure is initialized using NumberOfPackages, - GuidId, and the variable length argument list of package pointers. - - Then, EFI_HII_PACKAGE_LIST will be register to the default System HII Database. The - Handle to the newly registered Package List is returned through HiiHandle. - - If HiiHandle is NULL, then ASSERT. + // + // Allocate the storage for the entire Package List + // + PackageListHeader = AllocateZeroPool (Length); - @param NumberOfPackages The number of HII packages to register. - @param GuidId Package List GUID ID. - @param DriverHandle Optional. If not NULL, the DriverHandle on which an instance of DEVICE_PATH_PROTOCOL is installed. - This DriverHandle uniquely defines the device that the added packages are associated with. - @param HiiHandle On output, the HiiHandle is update with the handle which can be used to retrieve the Package - List later. If the functions failed to add the package to the default HII database, this value will - be set to NULL. - @param ... The variable argument list describing all HII Package. + // + // If the Packahge List can not be allocated, then return a NULL HII Handle + // + if (PackageListHeader == NULL) { + return NULL; + } - @return EFI_SUCCESS If the packages are successfully added to the default HII database. - @return EFI_OUT_OF_RESOURCE Not enough resource to complete the operation. + // + // Fill in the GUID and Length of the Package List Header + // + CopyGuid (&PackageListHeader->PackageListGuid, PackageListGuid); + PackageListHeader->PackageLength = Length; -**/ -EFI_STATUS -EFIAPI -HiiLibAddPackages ( - IN UINTN NumberOfPackages, - IN CONST EFI_GUID *GuidId, - IN EFI_HANDLE DriverHandle, OPTIONAL - OUT EFI_HII_HANDLE *HiiHandle, - ... - ) -{ - VA_LIST Args; - EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; - EFI_STATUS Status; + // + // Initialize a pointer to the beginning if the Package List data + // + Data = (UINT8 *)(PackageListHeader + 1); - ASSERT (HiiHandle != NULL); + // + // Copy the data from each package in the variable argument list + // + for (VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) { + Length = ReadUnaligned32 (Package) - sizeof (UINT32); + CopyMem (Data, Package + 1, Length); + Data += Length; + } + VA_END (Args); - VA_START (Args, HiiHandle); - PackageListHeader = InternalHiiLibPreparePackages (NumberOfPackages, GuidId, Args); + // + // Append a package of type EFI_HII_PACKAGE_END to mark the end of the package list + // + CopyMem (Data, &mEndOfPakageList, sizeof (mEndOfPakageList)); - Status = mHiiDatabaseProt->NewPackageList (mHiiDatabaseProt, PackageListHeader, DriverHandle, HiiHandle); - if (HiiHandle != NULL) { - if (EFI_ERROR (Status)) { - *HiiHandle = NULL; - } + // + // Register the package list with the HII Database + // + Status = gHiiDatabase->NewPackageList ( + gHiiDatabase, + PackageListHeader, + DeviceHandle, + &HiiHandle + ); + if (EFI_ERROR (Status)) { + HiiHandle = NULL; } + // + // Free the allocated package list + // FreePool (PackageListHeader); - VA_END (Args); - - return Status; + + // + // Return the new HII Handle + // + return HiiHandle; } /** - Removes a package list from the default HII database. + Removes a package list from the HII database. If HiiHandle is NULL, then ASSERT. - If HiiHandle is not a valid EFI_HII_HANDLE in the default HII database, then ASSERT. + If HiiHandle is not a valid EFI_HII_HANDLE in the HII database, then ASSERT. - @param HiiHandle The handle that was previously registered to the data base that is requested for removal. - List later. + @param[in] HiiHandle The handle that was previously registered in the HII database **/ VOID EFIAPI -HiiLibRemovePackages ( +HiiRemovePackages ( IN EFI_HII_HANDLE HiiHandle ) { EFI_STATUS Status; - ASSERT (IsHiiHandleRegistered (HiiHandle)); - Status = mHiiDatabaseProt->RemovePackageList (mHiiDatabaseProt, HiiHandle); + ASSERT (HiiHandle != NULL); + Status = gHiiDatabase->RemovePackageList (gHiiDatabase, HiiHandle); ASSERT_EFI_ERROR (Status); } /** - Determines the handles that are currently active in the database. - It's the caller's responsibility to free handle buffer. - - If HandleBufferLength is NULL, then ASSERT. - If HiiHandleBuffer is NULL, then ASSERT. - - @param HandleBufferLength On input, a pointer to the length of the handle - buffer. On output, the length of the handle buffer - that is required for the handles found. - @param HiiHandleBuffer Pointer to an array of Hii Handles returned. - - @retval EFI_SUCCESS Get an array of Hii Handles successfully. + Retrieves the array of all the HII Handles or the HII handle of a specific + package list in the HII Database. + This array is terminated with a NULL HII Handle. + This function allocates the returned array using AllocatePool(). + The caller is responsible for freeing the array with FreePool(). + + @param[in] PackageListGuid An optional parameter that is used to request + an HII Handle that is associatd with a specific + Package List GUID. If this parameter is NULL + then all the HII Handles in the HII Database + are returned. If this parameter is not NULL + then at most 1 HII Handle is returned. + + @retval NULL No HII handles were found in the HII database + @retval NULL The array of HII Handles could not be retrieved + @retval Other A pointer to the NULL terminated array of HII Handles **/ -EFI_STATUS +EFI_HII_HANDLE * EFIAPI -HiiLibGetHiiHandles ( - IN OUT UINTN *HandleBufferLength, - OUT EFI_HII_HANDLE **HiiHandleBuffer +HiiGetHiiHandles ( + IN CONST EFI_GUID *PackageListGuid OPTIONAL ) { - EFI_STATUS Status; + EFI_STATUS Status; + UINTN HandleBufferLength; + EFI_HII_HANDLE TempHiiHandleBuffer; + EFI_HII_HANDLE *HiiHandleBuffer; + EFI_GUID Guid; + UINTN Index; + + // + // Retrieve the size required for the buffer of all HII handles. + // + HandleBufferLength = 0; + Status = gHiiDatabase->ListPackageLists ( + gHiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &HandleBufferLength, + &TempHiiHandleBuffer + ); - ASSERT (HandleBufferLength != NULL); - ASSERT (HiiHandleBuffer != NULL); + // + // If ListPackageLists() returns EFI_SUCCESS for a zero size, + // then there are no HII handles in the HII database. If ListPackageLists() + // returns an error other than EFI_BUFFER_TOO_SMALL, then there are no HII + // handles in the HII database. + // + if (Status != EFI_BUFFER_TOO_SMALL) { + // + // Return NULL if the size can not be retrieved, or if there are no HII + // handles in the HII Database + // + return NULL; + } - *HandleBufferLength = 0; - *HiiHandleBuffer = NULL; + // + // Allocate the array of HII handles to hold all the HII Handles and a NULL terminator + // + HiiHandleBuffer = AllocateZeroPool (HandleBufferLength + sizeof (EFI_HII_HANDLE)); + if (HiiHandleBuffer == NULL) { + // + // Return NULL if allocation fails. + // + return NULL; + } // - // Try to find the actual buffer size for HiiHandle Buffer. + // Retrieve the array of HII Handles in the HII Database // - Status = mHiiDatabaseProt->ListPackageLists ( - mHiiDatabaseProt, - EFI_HII_PACKAGE_TYPE_ALL, - NULL, - HandleBufferLength, - *HiiHandleBuffer - ); - - if (Status == EFI_BUFFER_TOO_SMALL) { - *HiiHandleBuffer = AllocateZeroPool (*HandleBufferLength); - ASSERT (*HiiHandleBuffer != NULL); - Status = mHiiDatabaseProt->ListPackageLists ( - mHiiDatabaseProt, - EFI_HII_PACKAGE_TYPE_ALL, - NULL, - HandleBufferLength, - *HiiHandleBuffer - ); + Status = gHiiDatabase->ListPackageLists ( + gHiiDatabase, + EFI_HII_PACKAGE_TYPE_ALL, + NULL, + &HandleBufferLength, + HiiHandleBuffer + ); + if (EFI_ERROR (Status)) { + // + // Free the buffer and return NULL if the HII handles can not be retrieved. + // + FreePool (HiiHandleBuffer); + return NULL; + } - if (EFI_ERROR (Status)) { - FreePool (*HiiHandleBuffer); - *HiiHandleBuffer = NULL; + if (PackageListGuid == NULL) { + // + // Return the NULL terminated array of HII handles in the HII Database + // + return HiiHandleBuffer; + } else { + for (Index = 0; HiiHandleBuffer[Index] != NULL; Index++) { + Status = InternalHiiExtractGuidFromHiiHandle (HiiHandleBuffer[Index], &Guid); + ASSERT_EFI_ERROR (Status); + if (CompareGuid (&Guid, PackageListGuid)) { + HiiHandleBuffer[0] = HiiHandleBuffer[Index]; + HiiHandleBuffer[1] = NULL; + return HiiHandleBuffer; } + } + FreePool (HiiHandleBuffer); + return NULL; } - - return Status; } /** - Extract Hii package list GUID for given HII handle. + Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for + hex digits that appear between a '=' and a '&' in a config string. - If HiiHandle could not be found in the default HII database, then ASSERT. - If Guid is NULL, then ASSERT. + If String is NULL, then ASSERT(). - @param Handle Hii handle - @param Guid Package list GUID + @param[in] String Pointer to a Null-terminated Unicode string. - @retval EFI_SUCCESS Successfully extract GUID from Hii database. + @return Pointer to the Null-terminated Unicode result string. **/ -EFI_STATUS +EFI_STRING EFIAPI -HiiLibExtractGuidFromHiiHandle ( - IN EFI_HII_HANDLE Handle, - OUT EFI_GUID *Guid +InternalHiiLowerConfigString ( + IN EFI_STRING ConfigString ) { - EFI_STATUS Status; - UINTN BufferSize; - EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + EFI_STRING String; + BOOLEAN Lower; - ASSERT (Guid != NULL); - ASSERT (IsHiiHandleRegistered (Handle)); + ASSERT (ConfigString != NULL); // - // Get HII PackageList + // Convert all hex digits in range [A-F] in the configuration header to [a-f] // - BufferSize = 0; - HiiPackageList = NULL; - - Status = mHiiDatabaseProt->ExportPackageLists (mHiiDatabaseProt, Handle, &BufferSize, HiiPackageList); - ASSERT (Status != EFI_NOT_FOUND); - - if (Status == EFI_BUFFER_TOO_SMALL) { - HiiPackageList = AllocatePool (BufferSize); - ASSERT (HiiPackageList != NULL); - - Status = mHiiDatabaseProt->ExportPackageLists (mHiiDatabaseProt, Handle, &BufferSize, HiiPackageList); - } - if (EFI_ERROR (Status)) { - FreePool (HiiPackageList); - return Status; + for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { + if (*String == L'=') { + Lower = TRUE; + } else if (*String == L'&') { + Lower = FALSE; + } else if (Lower && *String >= L'A' && *String <= L'F') { + *String = (CHAR16) (*String - L'A' + L'a'); + } } - // - // Extract GUID - // - CopyGuid (Guid, &HiiPackageList->PackageListGuid); - - FreePool (HiiPackageList); - - return EFI_SUCCESS; + return ConfigString; } /** - Find HII Handle in the default HII database associated with given Device Path. + Uses the BlockToConfig() service of the Config Routing Protocol to + convert and a buffer to a - If DevicePath is NULL, then ASSERT. + If ConfigRequest is NULL, then ASSERT(). + If Block is NULL, then ASSERT(). - @param DevicePath Device Path associated with the HII package list - handle. + @param[in] ConfigRequest Pointer to a Null-terminated Unicode string. + @param[in] Block Pointer to a block of data. + @param[in] BlockSize The zie, in bytes, of Block. - @retval Handle HII package list Handle associated with the Device - Path. - @retval NULL Hii Package list handle is not found. + @retval NULL The string could not be generated. + @retval Other Pointer to the Null-terminated Unicode string. **/ -EFI_HII_HANDLE +EFI_STRING EFIAPI -HiiLibDevicePathToHiiHandle ( - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath +InternalHiiBlockToConfig ( + IN CONST EFI_STRING ConfigRequest, + IN CONST UINT8 *Block, + IN UINTN BlockSize ) { - EFI_STATUS Status; - EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; - UINTN BufferSize; - UINTN HandleCount; - UINTN Index; - EFI_HANDLE *Handles; - EFI_HANDLE Handle; - UINTN Size; - EFI_HANDLE DriverHandle; - EFI_HII_HANDLE *HiiHandles; - EFI_HII_HANDLE HiiHandle; + EFI_STATUS Status; + EFI_STRING ConfigResp; + CHAR16 *Progress; - ASSERT (DevicePath != NULL); + ASSERT (ConfigRequest != NULL); + ASSERT (Block != NULL); // - // Locate Device Path Protocol handle buffer + // Convert to // - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiDevicePathProtocolGuid, - NULL, - &HandleCount, - &Handles - ); + Status = gHiiConfigRouting->BlockToConfig ( + gHiiConfigRouting, + ConfigRequest, + Block, + BlockSize, + &ConfigResp, + &Progress + ); if (EFI_ERROR (Status)) { return NULL; } + return ConfigResp; +} + +/** + Uses the BrowserCallback() service of the Form Browser Protocol to retrieve + or set uncommitted data. If sata i being retrieved, then the buffer is + allocated using AllocatePool(). The caller is then responsible for freeing + the buffer using FreePool(). + + @param[in] VariableName Pointer to a Null-terminated Unicode string. This + is an optional parameter that may be NULL. + @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional + parameter that may be NULL. + @param[in] SetResultsData If not NULL, then this parameter specified the buffer + of uncommited data to set. If this parameter is NULL, + then the caller is requesting to get the uncommited data + from the Form Browser. + + @retval NULL The uncommitted data could not be retrieved. + @retval Other A pointer to a buffer containing the uncommitted data. + +**/ +EFI_STRING +EFIAPI +InternalHiiBrowserCallback ( + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName, OPTIONAL + IN CONST EFI_STRING SetResultsData OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN ResultsDataSize; + EFI_STRING ResultsData; + CHAR16 TempResultsData; // - // Search Driver Handle by Device Path + // Locate protocols // - DriverHandle = NULL; - BufferSize = GetDevicePathSize (DevicePath); - for(Index = 0; Index < HandleCount; Index++) { - Handle = Handles[Index]; - gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **) &TmpDevicePath); + if (mUefiFormBrowser2 == NULL) { + Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mUefiFormBrowser2); + if (EFI_ERROR (Status) || mUefiFormBrowser2 == NULL) { + return NULL; + } + } + ResultsDataSize = 0; + + if (SetResultsData != NULL) { // - // Check whether DevicePath match + // Request to to set data in the uncommitted browser state information // - Size = GetDevicePathSize (TmpDevicePath); - if ((Size == BufferSize) && CompareMem (DevicePath, TmpDevicePath, Size) == 0) { - DriverHandle = Handle; - break; + ResultsData = SetResultsData; + } else { + // + // Retrieve the length of the buffer required ResultsData from the Browser Callback + // + Status = mUefiFormBrowser2->BrowserCallback ( + mUefiFormBrowser2, + &ResultsDataSize, + &TempResultsData, + TRUE, + VariableGuid, + VariableName + ); + + if (!EFI_ERROR (Status)) { + // + // No Resluts Data, only allocate one char for '\0' + // + ResultsData = AllocateZeroPool (sizeof (CHAR16)); + return ResultsData; } - } - FreePool (Handles); - if (DriverHandle == NULL) { - return NULL; + if (Status != EFI_BUFFER_TOO_SMALL) { + return NULL; + } + + // + // Allocate the ResultsData buffer + // + ResultsData = AllocateZeroPool (ResultsDataSize); + if (ResultsData == NULL) { + return NULL; + } } // - // Retrieve all Hii Handles from HII database + // Retrieve or set the ResultsData from the Browser Callback // - BufferSize = 0x1000; - HiiHandles = AllocatePool (BufferSize); - ASSERT (HiiHandles != NULL); - Status = mHiiDatabaseProt->ListPackageLists ( - mHiiDatabaseProt, - EFI_HII_PACKAGE_TYPE_ALL, - NULL, - &BufferSize, - HiiHandles - ); - if (Status == EFI_BUFFER_TOO_SMALL) { - FreePool (HiiHandles); - HiiHandles = AllocatePool (BufferSize); - ASSERT (HiiHandles != NULL); - - Status = mHiiDatabaseProt->ListPackageLists ( - mHiiDatabaseProt, - EFI_HII_PACKAGE_TYPE_ALL, - NULL, - &BufferSize, - HiiHandles + Status = mUefiFormBrowser2->BrowserCallback ( + mUefiFormBrowser2, + &ResultsDataSize, + ResultsData, + (BOOLEAN)(SetResultsData == NULL), + VariableGuid, + VariableName ); - } - if (EFI_ERROR (Status)) { - FreePool (HiiHandles); return NULL; } - // - // Search Hii Handle by Driver Handle - // - HiiHandle = NULL; - HandleCount = BufferSize / sizeof (EFI_HII_HANDLE); - for (Index = 0; Index < HandleCount; Index++) { - Status = mHiiDatabaseProt->GetPackageListHandle ( - mHiiDatabaseProt, - HiiHandles[Index], - &Handle - ); - if (!EFI_ERROR (Status) && (Handle == DriverHandle)) { - HiiHandle = HiiHandles[Index]; - break; - } - } - - FreePool (HiiHandles); - return HiiHandle; + return ResultsData; } /** - Exports the contents of one or all package lists in the HII database into a buffer. - - If Handle is not NULL and not a valid EFI_HII_HANDLE registered in the database, - then ASSERT. - If PackageListHeader is NULL, then ASSERT. - If PackageListSize is NULL, then ASSERT. - - @param Handle The HII Handle. - @param PackageListHeader A pointer to a buffer that will contain the results of - the export function. - @param PackageListSize On output, the length of the buffer that is required for the exported data. - - @retval EFI_SUCCESS Package exported. - - @retval EFI_OUT_OF_RESOURCES Not enought memory to complete the operations. + Allocates and returns a Null-terminated Unicode string using routing + information that includes a GUID, an optional Unicode string name, and a device + path. The string returned is allocated with AllocatePool(). The caller is + responsible for freeing the allocated string with FreePool(). + + The format of a is as follows: + + GUID=32&NAME=NameLength&PATH=DevicePathSize + + @param[in] Guid Pointer to an EFI_GUID that is the routing information + GUID. Each of the 16 bytes in Guid is converted to + a 2 Unicode character hexidecimal string. This is + an optional parameter that may be NULL. + @param[in] Name Pointer to a Null-terminated Unicode string that is + the routing information NAME. This is an optional + parameter that may be NULL. Each 16-bit Unicode + character in Name is converted to a 4 character Unicode + hexidecimal string. + @param[in] DriverHandle The driver handle which supports a Device Path Protocol + that is the routing information PATH. Each byte of + the Device Path associated with DriverHandle is converted + to a 2 Unicode character hexidecimal string. + + @retval NULL DriverHandle does not support the Device Path Protocol. + @retval Other A pointer to the Null-terminate Unicode string **/ -EFI_STATUS +EFI_STRING EFIAPI -HiiLibExportPackageLists ( - IN EFI_HII_HANDLE Handle, - OUT EFI_HII_PACKAGE_LIST_HEADER **PackageListHeader, - OUT UINTN *PackageListSize +HiiConstructConfigHdr ( + IN CONST EFI_GUID *Guid, OPTIONAL + IN CONST CHAR16 *Name, OPTIONAL + IN EFI_HANDLE DriverHandle ) { - EFI_STATUS Status; - UINTN Size; - EFI_HII_PACKAGE_LIST_HEADER *PackageListHdr; - - ASSERT (PackageListSize != NULL); - ASSERT (PackageListHeader != NULL); + UINTN NameLength; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN DevicePathSize; + CHAR16 *String; + CHAR16 *ReturnString; + UINTN Index; + UINT8 *Buffer; - if (Handle != NULL) { - ASSERT (IsHiiHandleRegistered (Handle)); + // + // Compute the length of Name in Unicode characters. + // If Name is NULL, then the length is 0. + // + NameLength = 0; + if (Name != NULL) { + NameLength = StrLen (Name); } - Size = 0; - PackageListHdr = NULL; - Status = mHiiDatabaseProt->ExportPackageLists ( - mHiiDatabaseProt, - Handle, - &Size, - PackageListHdr - ); - ASSERT_EFI_ERROR (Status != EFI_BUFFER_TOO_SMALL); - - if (Status == EFI_BUFFER_TOO_SMALL) { - PackageListHdr = AllocateZeroPool (Size); - - if (PackageListHeader == NULL) { - return EFI_OUT_OF_RESOURCES; - } else { - Status = mHiiDatabaseProt->ExportPackageLists ( - mHiiDatabaseProt, - Handle, - &Size, - PackageListHdr - ); + DevicePath = NULL; + DevicePathSize = 0; + // + // Retrieve DevicePath Protocol associated with DriverHandle + // + if (DriverHandle != NULL) { + DevicePath = DevicePathFromHandle (DriverHandle); + if (DevicePath == NULL) { + return NULL; } + // + // Compute the size of the device path in bytes + // + DevicePathSize = GetDevicePathSize (DevicePath); } - if (!EFI_ERROR (Status)) { - *PackageListHeader = PackageListHdr; - *PackageListSize = Size; - } else { - FreePool (PackageListHdr); + // + // GUID=32&NAME=NameLength&PATH=DevicePathSize + // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 | + // + String = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16)); + if (String == NULL) { + return NULL; } - return Status; -} - -/** - - This function returns a list of the package handles of the - specified type that are currently active in the HII database. The - pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package - handles to be listed. + // + // Start with L"GUID=" + // + ReturnString = StrCpy (String, L"GUID="); + String += StrLen (String); - If HandleBufferLength is NULL, then ASSERT. - If HandleBuffer is NULL, the ASSERT. - If PackageType is EFI_HII_PACKAGE_TYPE_GUID and PackageGuid is - NULL, then ASSERT. - If PackageType is not EFI_HII_PACKAGE_TYPE_GUID and PackageGuid is not - NULL, then ASSERT. + if (Guid != NULL) { + // + // Append Guid converted to 32 + // + for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) { + String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); + } + } + + // + // Append L"&NAME=" + // + StrCpy (String, L"&NAME="); + String += StrLen (String); + + if (Name != NULL) { + // + // Append Name converted to NameLength + // + for (; *Name != L'\0'; Name++) { + String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4); + } + } + + // + // Append L"&PATH=" + // + StrCpy (String, L"&PATH="); + String += StrLen (String); + + // + // Append the device path associated with DriverHandle converted to DevicePathSize + // + for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) { + String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); + } + + // + // Null terminate the Unicode string + // + *String = L'\0'; + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + return InternalHiiLowerConfigString (ReturnString); +} + +/** + Convert the hex UNICODE encoding string of UEFI GUID, NAME or device path + to binary buffer from . + + This is a internal function. + + @param String UEFI configuration string. + @param Flag Flag specifies what type buffer will be retrieved. + @param Buffer Binary of Guid, Name or Device path. + + @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures. + @retval EFI_SUCCESS The buffer data is retrieved and translated to + binary format. + +**/ +EFI_STATUS +InternalHiiGetBufferFromString ( + IN EFI_STRING String, + IN UINT8 Flag, + OUT UINT8 **Buffer + ) +{ + UINTN Length; + EFI_STRING ConfigHdr; + CHAR16 *StringPtr; + UINT8 *DataBuffer; + CHAR16 TemStr[5]; + UINTN Index; + UINT8 DigitUint8; + + if (String == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + DataBuffer = NULL; + StringPtr = NULL; + ConfigHdr = String; + // + // The content between 'GUID', 'NAME', 'PATH' of and '&' of next element + // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding string. + // + for (Length = 0; *String != 0 && *String != L'&'; String++, Length++); + + switch (Flag) { + case GUID_CONFIG_STRING_TYPE: + case PATH_CONFIG_STRING_TYPE: + // + // The data in is encoded as hex UNICODE %02x bytes in the same order + // as the device path and Guid resides in RAM memory. + // Translate the data into binary. + // + DataBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2); + if (DataBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Convert binary byte one by one + // + ZeroMem (TemStr, sizeof (TemStr)); + for (Index = 0; Index < Length; Index ++) { + TemStr[0] = ConfigHdr[Index]; + DigitUint8 = (UINT8) StrHexToUint64 (TemStr); + if ((Index & 1) == 0) { + DataBuffer [Index/2] = DigitUint8; + } else { + DataBuffer [Index/2] = (UINT8) ((DataBuffer [Index/2] << 4) + DigitUint8); + } + } + + *Buffer = DataBuffer; + break; + + case NAME_CONFIG_STRING_TYPE: + // + // Convert Config String to Unicode String, e.g. "0041004200430044" => "ABCD" + // + + // + // Add the tailling char L'\0' + // + DataBuffer = (UINT8 *) AllocateZeroPool ((Length/4 + 1) * sizeof (CHAR16)); + if (DataBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Convert character one by one + // + StringPtr = (CHAR16 *) DataBuffer; + ZeroMem (TemStr, sizeof (TemStr)); + for (Index = 0; Index < Length; Index += 4) { + StrnCpy (TemStr, ConfigHdr + Index, 4); + StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr); + } + // + // Add tailing L'\0' character + // + StringPtr[Index/4] = L'\0'; + + *Buffer = DataBuffer; + break; + + default: + return EFI_INVALID_PARAMETER; + break; + } + + return EFI_SUCCESS; +} + +/** + This function checks VarOffset and VarWidth is in the block range. + + @param BlockArray The block array is to be checked. + @param VarOffset Offset of var to the structure + @param VarWidth Width of var. - @param PackageType Specifies the package type of the packages - to list or EFI_HII_PACKAGE_TYPE_ALL for - all packages to be listed. + @retval TRUE This Var is in the block range. + @retval FALSE This Var is not in the block range. +**/ +BOOLEAN +BlockArrayCheck ( + IN IFR_BLOCK_DATA *BlockArray, + IN UINT16 VarOffset, + IN UINT16 VarWidth + ) +{ + LIST_ENTRY *Link; + IFR_BLOCK_DATA *BlockData; - @param PackageGuid If PackageType is - EFI_HII_PACKAGE_TYPE_GUID, then this is - the pointer to the GUID which must match - the Guid field of - EFI_HII_PACKAGE_GUID_HEADER. Otherwise, it - must be NULL. + // + // No Request Block array, all vars are got. + // + if (BlockArray == NULL) { + return TRUE; + } - @param HandleBufferLength On output, the length of the handle buffer - that is required for the handles found. + // + // Check the input var is in the request block range. + // + for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) { + BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); + if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) { + return TRUE; + } + } + + return FALSE; +} - @param HandleBuffer On output, an array of EFI_HII_HANDLE instances returned. - The caller is responcible to free this pointer allocated. +/** + Get the value of in format, i.e. the value of OFFSET + or WIDTH or VALUE. + ::= 'OFFSET='&'WIDTH='&'VALUE'= + + @param ValueString String in format and points to the + first character of . + @param ValueData The output value. Caller takes the responsibility + to free memory. + @param ValueLength Length of the , in characters. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary + structures. + @retval EFI_SUCCESS Value of is outputted in Number + successfully. - @retval EFI_SUCCESS The matching handles are outputed successfully. - HandleBufferLength is updated with the actual length. - @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operation. - @retval EFI_NOT_FOUND No matching handle could not be found in database. **/ EFI_STATUS EFIAPI -HiiLibListPackageLists ( - IN UINT8 PackageType, - IN CONST EFI_GUID *PackageGuid, - IN OUT UINTN *HandleBufferLength, - OUT EFI_HII_HANDLE **HandleBuffer +InternalHiiGetValueOfNumber ( + IN EFI_STRING ValueString, + OUT UINT8 **ValueData, + OUT UINTN *ValueLength ) { - EFI_STATUS Status; + EFI_STRING StringPtr; + UINTN Length; + UINT8 *Buf; + UINT8 DigitUint8; + UINTN Index; + CHAR16 TemStr[2]; + + ASSERT (ValueString != NULL && ValueData != NULL && ValueLength != NULL); + ASSERT (*ValueString != L'\0'); + + // + // Get the length of value string + // + StringPtr = ValueString; + while (*StringPtr != L'\0' && *StringPtr != L'&') { + StringPtr++; + } + Length = StringPtr - ValueString; + + // + // Allocate buffer to store the value + // + Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2); + if (Buf == NULL) { + return EFI_OUT_OF_RESOURCES; + } - ASSERT (HandleBufferLength != NULL); - ASSERT (HandleBuffer != NULL); + // + // Convert character one by one to the value buffer + // + ZeroMem (TemStr, sizeof (TemStr)); + for (Index = 0; Index < Length; Index ++) { + TemStr[0] = ValueString[Length - Index - 1]; + DigitUint8 = (UINT8) StrHexToUint64 (TemStr); + if ((Index & 1) == 0) { + Buf [Index/2] = DigitUint8; + } else { + Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]); + } + } - *HandleBufferLength = 0; - *HandleBuffer = NULL; + // + // Set the converted value and string length. + // + *ValueData = Buf; + *ValueLength = Length; + return EFI_SUCCESS; +} - if (PackageType == EFI_HII_PACKAGE_TYPE_GUID) { - ASSERT (PackageGuid != NULL); - } else { - ASSERT (PackageGuid == NULL); +/** + This internal function parses IFR data to validate current setting. + + @param ConfigResp ConfigResp string contains the current setting. + @param HiiPackageList Point to Hii package list. + @param PackageListLength The length of the pacakge. + @param VarGuid Guid of the buffer storage. + @param VarName Name of the buffer storage. + + @retval EFI_SUCCESS The current setting is valid. + @retval EFI_OUT_OF_RESOURCES The memory is not enough. + @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid. +**/ +EFI_STATUS +EFIAPI +InternalHiiValidateCurrentSetting ( + IN EFI_STRING ConfigResp, + IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList, + IN UINTN PackageListLength, + IN EFI_GUID *VarGuid, + IN CHAR16 *VarName + ) +{ + IFR_BLOCK_DATA *CurrentBlockArray; + IFR_BLOCK_DATA *BlockData; + IFR_BLOCK_DATA *NewBlockData; + IFR_BLOCK_DATA VarBlockData; + EFI_STRING StringPtr; + UINTN Length; + UINT8 *TmpBuffer; + UINT16 Offset; + UINT16 Width; + UINT64 VarValue; + LIST_ENTRY *Link; + UINT8 *VarBuffer; + UINTN MaxBufferSize; + EFI_STATUS Status; + EFI_HII_PACKAGE_HEADER PacakgeHeader; + UINT32 PackageOffset; + UINT8 *PackageData; + UINTN IfrOffset; + EFI_IFR_OP_HEADER *IfrOpHdr; + EFI_IFR_VARSTORE *IfrVarStore; + EFI_IFR_ONE_OF *IfrOneOf; + EFI_IFR_NUMERIC *IfrNumeric; + EFI_IFR_ONE_OF_OPTION *IfrOneOfOption; + EFI_IFR_CHECKBOX *IfrCheckBox; + EFI_IFR_STRING *IfrString; + CHAR8 *VarStoreName; + UINTN Index; + + // + // 1. Get the current setting to current block data array and Convert them into VarBuffer + // + + // + // Skip ConfigHdr string + // + StringPtr = ConfigResp; + StringPtr = StrStr (ConfigResp, L"&OFFSET"); + if (StringPtr == NULL) { + // + // No ConfigBlock value is requied to be validated. + // EFI_SUCCESS directly return. + // + return EFI_SUCCESS; + } + + // + // Initialize the local variables. + // + Index = 0; + VarStoreName = NULL; + Status = EFI_SUCCESS; + BlockData = NULL; + NewBlockData = NULL; + TmpBuffer = NULL; + MaxBufferSize = HII_LIB_DEFAULT_VARSTORE_SIZE; + VarBuffer = AllocateZeroPool (MaxBufferSize); + if (VarBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; } - Status = mHiiDatabaseProt->ListPackageLists ( - mHiiDatabaseProt, - PackageType, - PackageGuid, - HandleBufferLength, - *HandleBuffer - ); - if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) { + // + // Init CurrentBlockArray + // + CurrentBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); + if (CurrentBlockArray == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + InitializeListHead (&CurrentBlockArray->Entry); + + // + // Parse each if exists + // Only format is supported by this help function. + // ::= &'OFFSET='&'WIDTH=' + // + while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) { // - // No packages is registered to UEFI HII Database, just return. + // Skip the &OFFSET= string // + StringPtr += StrLen (L"&OFFSET="); + + // + // Get Offset + // + Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length); + if (EFI_ERROR (Status)) { + goto Done; + } + Offset = 0; + CopyMem ( + &Offset, + TmpBuffer, + (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16) + ); + FreePool (TmpBuffer); + TmpBuffer = NULL; + + StringPtr += Length; + if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr += StrLen (L"&WIDTH="); + + // + // Get Width + // + Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length); + if (EFI_ERROR (Status)) { + goto Done; + } + Width = 0; + CopyMem ( + &Width, + TmpBuffer, + (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16) + ); + FreePool (TmpBuffer); + TmpBuffer = NULL; + + StringPtr += Length; + if (*StringPtr != 0 && *StringPtr != L'&') { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr += StrLen (L"&VALUE="); + + // + // Get Value + // + Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length); + if (EFI_ERROR (Status)) { + goto Done; + } + + StringPtr += Length; + if (*StringPtr != 0 && *StringPtr != L'&') { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Check whether VarBuffer is enough + // + if ((UINTN) (Offset + Width) > MaxBufferSize) { + VarBuffer = ReallocatePool ( + MaxBufferSize, + Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE, + VarBuffer + ); + if (VarBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + MaxBufferSize = Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE; + } + + // + // Update the Block with configuration info + // + CopyMem (VarBuffer + Offset, TmpBuffer, Width); + FreePool (TmpBuffer); + TmpBuffer = NULL; + + // + // Set new Block Data + // + NewBlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); + if (NewBlockData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + NewBlockData->Offset = Offset; + NewBlockData->Width = Width; + + // + // Insert the new block data into the block data array. + // + for (Link = CurrentBlockArray->Entry.ForwardLink; Link != &CurrentBlockArray->Entry; Link = Link->ForwardLink) { + BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); + if (NewBlockData->Offset == BlockData->Offset) { + if (NewBlockData->Width > BlockData->Width) { + BlockData->Width = NewBlockData->Width; + } + FreePool (NewBlockData); + break; + } else if (NewBlockData->Offset < BlockData->Offset) { + // + // Insert new block data as the previous one of this link. + // + InsertTailList (Link, &NewBlockData->Entry); + break; + } + } + + // + // Insert new block data into the array tail. + // + if (Link == &CurrentBlockArray->Entry) { + InsertTailList (Link, &NewBlockData->Entry); + } + + // + // If '\0', parsing is finished. + // + if (*StringPtr == 0) { + break; + } + // + // Go to next ConfigBlock // - return Status; } - *HandleBuffer = AllocateZeroPool (*HandleBufferLength); - - if (*HandleBuffer == NULL) { - return EFI_OUT_OF_RESOURCES; + // + // Merge the aligned block data into the single block data. + // + Link = CurrentBlockArray->Entry.ForwardLink; + while ((Link != &CurrentBlockArray->Entry) && (Link->ForwardLink != &CurrentBlockArray->Entry)) { + BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); + NewBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry); + if ((NewBlockData->Offset >= BlockData->Offset) && (NewBlockData->Offset <= (BlockData->Offset + BlockData->Width))) { + if ((NewBlockData->Offset + NewBlockData->Width) > (BlockData->Offset + BlockData->Width)) { + BlockData->Width = (UINT16) (NewBlockData->Offset + NewBlockData->Width - BlockData->Offset); + } + RemoveEntryList (Link->ForwardLink); + FreePool (NewBlockData); + continue; + } + Link = Link->ForwardLink; } - return mHiiDatabaseProt->ListPackageLists ( - mHiiDatabaseProt, - PackageType, - PackageGuid, - HandleBufferLength, - *HandleBuffer - ); + if (IsListEmpty (&CurrentBlockArray->Entry)) { + Status = EFI_SUCCESS; + goto Done; + } + + // + // 2. Check IFR value is in block data, then Validate Vaule + // + ZeroMem (&VarBlockData, sizeof (VarBlockData)); + VarValue = 0; + IfrVarStore = NULL; + PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + while (PackageOffset < PackageListLength) { + CopyMem (&PacakgeHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PacakgeHeader)); + + // + // Parse IFR opcode from the form package. + // + if (PacakgeHeader.Type == EFI_HII_PACKAGE_FORMS) { + IfrOffset = sizeof (PacakgeHeader); + PackageData = (UINT8 *) HiiPackageList + PackageOffset; + while (IfrOffset < PacakgeHeader.Length) { + IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset); + // + // Validate current setting to the value built in IFR opcode + // + switch (IfrOpHdr->OpCode) { + case EFI_IFR_VARSTORE_OP: + // + // VarStoreId has been found. No further found. + // + if (IfrVarStore != NULL) { + break; + } + // + // Find the matched VarStoreId to the input VarGuid and VarName + // + IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr; + if (CompareGuid ((EFI_GUID *) (VOID *) &IfrVarStore->Guid, VarGuid)) { + VarStoreName = (CHAR8 *) IfrVarStore->Name; + for (Index = 0; VarStoreName[Index] != 0; Index ++) { + if ((CHAR16) VarStoreName[Index] != VarName[Index]) { + break; + } + } + // + // The matched VarStore is found. + // + if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) { + IfrVarStore = NULL; + } + } else { + IfrVarStore = NULL; + } + break; + case EFI_IFR_FORM_OP: + // + // Check the matched VarStoreId is found. + // + if (IfrVarStore == NULL) { + Status = EFI_SUCCESS; + goto Done; + } + break; + case EFI_IFR_ONE_OF_OP: + // + // Check whether current value is the one of option. + // + + // + // OneOf question is not in IFR Form. This IFR form is not valid. + // + if (IfrVarStore == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + // + // Check whether this question is for the requested varstore. + // + IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr; + if (IfrOneOf->Question.VarStoreId != IfrVarStore->VarStoreId) { + break; + } + + // + // Get Offset by Question header and Width by DataType Flags + // + Offset = IfrOneOf->Question.VarStoreInfo.VarOffset; + Width = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE)); + // + // Check whether this question is in current block array. + // + if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) { + // + // This question is not in the current configuration string. Skip it. + // + break; + } + // + // Check this var question is in the var storage + // + if ((Offset + Width) > IfrVarStore->Size) { + // + // This question exceeds the var store size. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Get the current value for oneof opcode + // + VarValue = 0; + CopyMem (&VarValue, VarBuffer + Offset, Width); + // + // Set Block Data, to be checked in the following Oneof option opcode. + // + VarBlockData.Offset = Offset; + VarBlockData.Width = Width; + VarBlockData.OpCode = IfrOpHdr->OpCode; + VarBlockData.Scope = IfrOpHdr->Scope; + break; + case EFI_IFR_NUMERIC_OP: + // + // Check the current value is in the numeric range. + // + + // + // Numeric question is not in IFR Form. This IFR form is not valid. + // + if (IfrVarStore == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + // + // Check whether this question is for the requested varstore. + // + IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr; + if (IfrNumeric->Question.VarStoreId != IfrVarStore->VarStoreId) { + break; + } + + // + // Get Offset by Question header and Width by DataType Flags + // + Offset = IfrNumeric->Question.VarStoreInfo.VarOffset; + Width = (UINT16) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE)); + // + // Check whether this question is in current block array. + // + if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) { + // + // This question is not in the current configuration string. Skip it. + // + break; + } + // + // Check this var question is in the var storage + // + if ((Offset + Width) > IfrVarStore->Size) { + // + // This question exceeds the var store size. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Check the current value is in the numeric range. + // + VarValue = 0; + CopyMem (&VarValue, VarBuffer + Offset, Width); + switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + if ((UINT8) VarValue < IfrNumeric->data.u8.MinValue || (UINT8) VarValue > IfrNumeric->data.u8.MaxValue) { + // + // Not in the valid range. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + break; + case EFI_IFR_NUMERIC_SIZE_2: + if ((UINT16) VarValue < IfrNumeric->data.u16.MinValue || (UINT16) VarValue > IfrNumeric->data.u16.MaxValue) { + // + // Not in the valid range. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + break; + case EFI_IFR_NUMERIC_SIZE_4: + if ((UINT32) VarValue < IfrNumeric->data.u32.MinValue || (UINT32) VarValue > IfrNumeric->data.u32.MaxValue) { + // + // Not in the valid range. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + break; + case EFI_IFR_NUMERIC_SIZE_8: + if ((UINT64) VarValue < IfrNumeric->data.u64.MinValue || (UINT64) VarValue > IfrNumeric->data.u64.MaxValue) { + // + // Not in the valid range. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + break; + } + + break; + case EFI_IFR_CHECKBOX_OP: + // + // Check value is BOOLEAN type, only 0 and 1 is valid. + // + + // + // CheckBox question is not in IFR Form. This IFR form is not valid. + // + if (IfrVarStore == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Check whether this question is for the requested varstore. + // + IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr; + if (IfrCheckBox->Question.VarStoreId != IfrVarStore->VarStoreId) { + break; + } + + // + // Get Offset by Question header + // + Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset; + Width = sizeof (BOOLEAN); + // + // Check whether this question is in current block array. + // + if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) { + // + // This question is not in the current configuration string. Skip it. + // + break; + } + // + // Check this var question is in the var storage + // + if ((Offset + Width) > IfrVarStore->Size) { + // + // This question exceeds the var store size. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Boolean type, only 1 and 0 is valid. + // + if (*(VarBuffer + Offset) > 1) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + break; + case EFI_IFR_STRING_OP: + // + // Check current string length is less than maxsize + // + + // + // CheckBox question is not in IFR Form. This IFR form is not valid. + // + if (IfrVarStore == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Check whether this question is for the requested varstore. + // + IfrString = (EFI_IFR_STRING *) IfrOpHdr; + if (IfrString->Question.VarStoreId != IfrVarStore->VarStoreId) { + break; + } + + // + // Get Offset/Width by Question header and OneOf Flags + // + Offset = IfrString->Question.VarStoreInfo.VarOffset; + Width = (UINT16) (IfrString->MaxSize * sizeof (UINT16)); + // + // Check whether this question is in current block array. + // + if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) { + // + // This question is not in the current configuration string. Skip it. + // + break; + } + // + // Check this var question is in the var storage + // + if ((Offset + Width) > IfrVarStore->Size) { + // + // This question exceeds the var store size. + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Check current string length is less than maxsize + // + if (StrSize ((CHAR16 *) (VarBuffer + Offset)) > Width) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + break; + case EFI_IFR_ONE_OF_OPTION_OP: + // + // Opcode Scope is zero. This one of option is not to be checked. + // + if (VarBlockData.Scope == 0) { + break; + } + + // + // Only check for OneOf and OrderList opcode + // + IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr; + if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) { + // + // Check current value is the value of one of option. + // + if (VarValue == IfrOneOfOption->Value.u64) { + // + // The value is one of option value. + // Set OpCode to Zero, don't need check again. + // + VarBlockData.OpCode = 0; + } + } + + break; + case EFI_IFR_END_OP: + // + // Decrease opcode scope for the validated opcode + // + if (VarBlockData.Scope > 0) { + VarBlockData.Scope --; + } + + // + // OneOf value doesn't belong to one of option value. + // + if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + break; + default: + // + // Increase Scope for the validated opcode + // + if (VarBlockData.Scope > 0) { + VarBlockData.Scope = (UINT8) (VarBlockData.Scope + IfrOpHdr->Scope); + } + break; + } + // + // Go to the next opcode + // + IfrOffset += IfrOpHdr->Length; + } + // + // Only one form is in a package list. + // + break; + } + + // + // Go to next package. + // + PackageOffset += PacakgeHeader.Length; + } + +Done: + if (VarBuffer != NULL) { + FreePool (VarBuffer); + } + if (CurrentBlockArray != NULL) { + // + // Free Link Array CurrentBlockArray + // + while (!IsListEmpty (&CurrentBlockArray->Entry)) { + BlockData = BASE_CR (CurrentBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry); + RemoveEntryList (&BlockData->Entry); + FreePool (BlockData); + } + FreePool (CurrentBlockArray); + } + + return Status; } + /** - This function check if the Hii Handle is a valid handle registered - in the HII database. + This function parses the input ConfigRequest string and its matched IFR code + string for setting default value and validating current setting. - @param HiiHandle The HII Handle. + 1. For setting default action, Reset the default value specified by DefaultId + to the driver configuration got by Request string. + 2. For validating current setting, Validate the current configuration + by parsing HII form IFR opcode. - @retval TRUE If it is a valid HII handle. - @retval FALSE If it is a invalid HII handle. + NULL request string support depends on the ExportConfig interface of + HiiConfigRouting protocol in UEFI specification. + + @param Request A null-terminated Unicode string in + format. It can be NULL. + If it is NULL, all current configuration for the + entirety of the current HII database will be validated. + If it is NULL, all configuration for the + entirety of the current HII database will be reset. + @param DefaultId Specifies the type of defaults to retrieve only for setting default action. + @param ActionType Action supports setting defaults and validate current setting. + + @retval TURE Action runs successfully. + @retval FALSE Action is not valid or Action can't be executed successfully.. **/ BOOLEAN -IsHiiHandleRegistered ( - EFI_HII_HANDLE HiiHandle +EFIAPI +InternalHiiIfrValueAction ( + IN CONST EFI_STRING Request, OPTIONAL + IN UINT16 DefaultId, + IN UINT8 ActionType ) { - EFI_STATUS Status; - UINTN BufferSize; + EFI_STRING ConfigAltResp; + EFI_STRING ConfigAltHdr; + EFI_STRING ConfigResp; + EFI_STRING Progress; + EFI_STRING StringPtr; + EFI_STRING StringHdr; + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + EFI_HANDLE TempDriverHandle; + EFI_HII_HANDLE *HiiHandleBuffer; + EFI_HII_HANDLE HiiHandle; + UINT32 Index; + EFI_GUID *VarGuid; + EFI_STRING VarName; + EFI_STRING_ID DefaultName; + + UINT8 *PackageData; + UINTN IfrOffset; + EFI_IFR_OP_HEADER *IfrOpHdr; EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINT32 PackageOffset; + UINTN PackageListLength; + EFI_HII_PACKAGE_HEADER PacakgeHeader; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + ConfigAltResp = NULL; + ConfigResp = NULL; + VarGuid = NULL; + VarName = NULL; + DevicePath = NULL; + ConfigAltHdr = NULL; + HiiHandleBuffer = NULL; + Index = 0; + TempDriverHandle = NULL; + HiiHandle = NULL; + PackageData = NULL; + HiiPackageList = NULL; + + // + // Only support set default and validate setting action. + // + if ((ActionType != ACTION_SET_DEFAUTL_VALUE) && (ActionType != ACTION_VALIDATE_SETTING)) { + return FALSE; + } - ASSERT (HiiHandle != NULL); + // + // Get the full requested value and deault value string. + // + if (Request != NULL) { + Status = gHiiConfigRouting->ExtractConfig ( + gHiiConfigRouting, + Request, + &Progress, + &ConfigAltResp + ); + } else { + Status = gHiiConfigRouting->ExportConfig ( + gHiiConfigRouting, + &ConfigAltResp + ); + } + + if (EFI_ERROR (Status)) { + return FALSE; + } + + StringPtr = ConfigAltResp; + + while (StringPtr != L'\0') { + // + // 1. Find GUID=...&NAME=...&PATH=... + // + StringHdr = StringPtr; - HiiPackageList = NULL; - BufferSize = 0; + // + // Get Guid value + // + if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr += StrLen (L"GUID="); + Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid); + if (EFI_ERROR (Status)) { + goto Done; + } - Status = mHiiDatabaseProt->ExportPackageLists ( - mHiiDatabaseProt, - HiiHandle, - &BufferSize, - HiiPackageList - ); + // + // Get Name value VarName + // + while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) { + StringPtr++; + } + if (*StringPtr == L'\0') { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr += StrLen (L"&NAME="); + Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Get Path value DevicePath + // + while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) { + StringPtr++; + } + if (*StringPtr == L'\0') { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr += StrLen (L"&PATH="); + Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath); + if (EFI_ERROR (Status)) { + goto Done; + } - return (BOOLEAN) (Status == EFI_BUFFER_TOO_SMALL); -} + // + // Get the Driver handle by the got device path. + // + TempDevicePath = DevicePath; + Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Find the matched Hii Handle for the found Driver handle + // + HiiHandleBuffer = HiiGetHiiHandles (NULL); + if (HiiHandleBuffer == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) { + gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle); + if (TempDriverHandle == DriverHandle) { + break; + } + } + + HiiHandle = HiiHandleBuffer[Index]; + FreePool (HiiHandleBuffer); + + if (HiiHandle == NULL) { + // + // This request string has no its Hii package. + // Its default value and validating can't execute by parsing IFR data. + // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path. + // + Status = EFI_SUCCESS; + goto NextConfigAltResp; + } + + // + // 2. Get DefaultName string ID by parsing the PacakgeList + // + + // + // Get HiiPackage by HiiHandle + // + PackageListLength = 0; + HiiPackageList = NULL; + Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList); + + // + // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0. + // + if (Status != EFI_BUFFER_TOO_SMALL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + HiiPackageList = AllocatePool (PackageListLength); + if (HiiPackageList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Get PackageList on HiiHandle + // + Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Parse the form package and get the default name string ID. + // + if (ActionType == ACTION_SET_DEFAUTL_VALUE) { + PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Status = EFI_NOT_FOUND; + while (PackageOffset < PackageListLength) { + CopyMem (&PacakgeHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PacakgeHeader)); + + // + // Parse IFR opcode to get default store opcode + // + if (PacakgeHeader.Type == EFI_HII_PACKAGE_FORMS) { + IfrOffset = sizeof (PacakgeHeader); + PackageData = (UINT8 *) HiiPackageList + PackageOffset; + while (IfrOffset < PacakgeHeader.Length) { + IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset); + // + // Match DefaultId to find its DefaultName + // + if (IfrOpHdr->OpCode == EFI_IFR_DEFAULTSTORE_OP) { + if (((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId == DefaultId) { + DefaultName = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultName; + Status = EFI_SUCCESS; + break; + } + } + IfrOffset += IfrOpHdr->Length; + } + // + // Only one form is in a package list. + // + break; + } + + // + // Go to next package. + // + PackageOffset += PacakgeHeader.Length; + } + + // + // Not found the matched default string ID + // + if (EFI_ERROR (Status)) { + Status = EFI_SUCCESS; + goto NextConfigAltResp; + } + } + + // + // 3. Call ConfigRouting GetAltCfg(ConfigRoute, , Guid, Name, DevicePath, AltCfgId, AltCfgResp) + // Get the default configuration string according to the found defaultname string ID. + // + Status = gHiiConfigRouting->GetAltConfig ( + gHiiConfigRouting, + ConfigAltResp, + VarGuid, + VarName, + DevicePath, + (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultName:NULL, // it can be NULL to get the current setting. + &ConfigResp + ); + + // + // The required setting can't be found. So, it is not required to be validated and set. + // + if (EFI_ERROR (Status)) { + Status = EFI_SUCCESS; + goto NextConfigAltResp; + } + // + // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set. + // + if (StrStr (ConfigResp, L"&OFFSET=") == NULL) { + goto NextConfigAltResp; + } + + // + // 4. Set the default configuration information or Validate current setting by parse IFR code. + // Current Setting is in ConfigResp, will be set into buffer, then check it again. + // + if (ActionType == ACTION_SET_DEFAUTL_VALUE) { + // + // Set the default configuration information. + // + Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress); + } else { + // + // Current Setting is in ConfigResp, will be set into buffer, then check it again. + // + Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName); + } + + if (EFI_ERROR (Status)) { + goto Done; + } + +NextConfigAltResp: + // + // Free the allocated pacakge buffer and the got ConfigResp string. + // + if (HiiPackageList != NULL) { + FreePool (HiiPackageList); + HiiPackageList = NULL; + } + + if (ConfigResp != NULL) { + FreePool (ConfigResp); + ConfigResp = NULL; + } + + // + // Free the allocated buffer. + // + FreePool (VarGuid); + VarGuid = NULL; + + FreePool (VarName); + VarName = NULL; + + FreePool (DevicePath); + DevicePath = NULL; + + // + // 5. Jump to next ConfigAltResp for another Guid, Name, Path. + // + + // + // Get and Skip ConfigHdr + // + while (*StringPtr != L'\0' && *StringPtr != L'&') { + StringPtr++; + } + if (*StringPtr == L'\0') { + break; + } + + // + // Construct ConfigAltHdr string "&&ALTCFG=\0" + // | 1 | StrLen (ConfigHdr) | 8 | 1 | + // + ConfigAltHdr = AllocateZeroPool ((1 + StringPtr - StringHdr + 8 + 1) * sizeof (CHAR16)); + if (ConfigAltHdr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + StrCpy (ConfigAltHdr, L"&"); + StrnCat (ConfigAltHdr, StringHdr, StringPtr - StringHdr); + StrCat (ConfigAltHdr, L"&ALTCFG="); + + // + // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr + // + while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) { + StringPtr = StringHdr + StrLen (ConfigAltHdr); + if (*StringPtr == L'\0') { + break; + } + } + + // + // Free the allocated ConfigAltHdr string + // + FreePool (ConfigAltHdr); + if (*StringPtr == L'\0') { + break; + } + + // + // Find &GUID as the next ConfigHdr + // + StringPtr = StrStr (StringPtr, L"&GUID"); + if (StringPtr == NULL) { + break; + } + + // + // Skip char '&' + // + StringPtr ++; + } + +Done: + if (VarGuid != NULL) { + FreePool (VarGuid); + } + + if (VarName != NULL) { + FreePool (VarName); + } + + if (DevicePath != NULL) { + FreePool (DevicePath); + } + + if (ConfigResp != NULL) { + FreePool (ConfigResp); + } + + if (ConfigAltResp != NULL) { + FreePool (ConfigAltResp); + } + + if (HiiPackageList != NULL) { + FreePool (HiiPackageList); + } + + if (EFI_ERROR (Status)) { + return FALSE; + } + + return TRUE; +} + +/** + Validate the current configuration by parsing HII form IFR opcode. + + NULL request string support depends on the ExtractConfig interface of + HiiConfigRouting protocol in UEFI specification. + + @param Request A null-terminated Unicode string in + format. It can be NULL. + If it is NULL, all current configuration for the + entirety of the current HII database will be validated. + + @retval TURE Current configuration is valid. + @retval FALSE Current configuration is invalid. +**/ +BOOLEAN +EFIAPI +HiiValidateSettings ( + IN CONST EFI_STRING Request OPTIONAL + ) +{ + return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING); +} + +/** + Reset the default value specified by DefaultId to the driver + configuration got by Request string. + + NULL request string support depends on the ExportConfig interface of + HiiConfigRouting protocol in UEFI specification. + + @param Request A null-terminated Unicode string in + format. It can be NULL. + If it is NULL, all configuration for the + entirety of the current HII database will be reset. + @param DefaultId Specifies the type of defaults to retrieve. + + @retval TURE The default value is set successfully. + @retval FALSE The default value can't be found and set. +**/ +BOOLEAN +EFIAPI +HiiSetToDefaults ( + IN CONST EFI_STRING Request, OPTIONAL + IN UINT16 DefaultId + ) +{ + return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE); +} + +/** + Determines if two values in config strings match. + + Compares the substring between StartSearchString and StopSearchString in + FirstString to the substring between StartSearchString and StopSearchString + in SecondString. If the two substrings match, then TRUE is returned. If the + two substrings do not match, then FALSE is returned. + + If FirstString is NULL, then ASSERT(). + If SecondString is NULL, then ASSERT(). + If StartSearchString is NULL, then ASSERT(). + If StopSearchString is NULL, then ASSERT(). + + @param FirstString Pointer to the first Null-terminated Unicode string. + @param SecondString Pointer to the second Null-terminated Unicode string. + @param StartSearchString Pointer to the Null-terminated Unicode string that + marks the start of the value string to compare. + @param StopSearchString Pointer to the Null-terminated Unicode string that + marks the end of the vakue string to compare. + + @retval FALSE StartSearchString is not present in FirstString. + @retval FALSE StartSearchString is not present in SecondString. + @retval FALSE StopSearchString is not present in FirstString. + @retval FALSE StopSearchString is not present in SecondString. + @retval FALSE The length of the substring in FirstString is not the + same length as the substring in SecondString. + @retval FALSE The value string in FirstString does not matche the + value string in SecondString. + @retval TRUE The value string in FirstString matches the value + string in SecondString. + +**/ +BOOLEAN +EFIAPI +InternalHiiCompareSubString ( + IN CHAR16 *FirstString, + IN CHAR16 *SecondString, + IN CHAR16 *StartSearchString, + IN CHAR16 *StopSearchString + ) +{ + CHAR16 *EndFirstString; + CHAR16 *EndSecondString; + + ASSERT (FirstString != NULL); + ASSERT (SecondString != NULL); + ASSERT (StartSearchString != NULL); + ASSERT (StopSearchString != NULL); + + FirstString = StrStr (FirstString, StartSearchString); + if (FirstString == NULL) { + return FALSE; + } + + SecondString = StrStr (SecondString, StartSearchString); + if (SecondString == NULL) { + return FALSE; + } + + EndFirstString = StrStr (FirstString, StopSearchString); + if (EndFirstString == NULL) { + return FALSE; + } + + EndSecondString = StrStr (SecondString, StopSearchString); + if (EndSecondString == NULL) { + return FALSE; + } + + if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) { + return FALSE; + } + + return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0); +} + +/** + Determines if the routing data specified by GUID and NAME match a . + + If ConfigHdr is NULL, then ASSERT(). + + @param[in] ConfigHdr Either or . + @param[in] Guid GUID of the storage. + @param[in] Name NAME of the storage. + + @retval TRUE Routing information matches . + @retval FALSE Routing information does not match . + +**/ +BOOLEAN +EFIAPI +HiiIsConfigHdrMatch ( + IN CONST EFI_STRING ConfigHdr, + IN CONST EFI_GUID *Guid, OPTIONAL + IN CONST CHAR16 *Name OPTIONAL + ) +{ + EFI_STRING CompareConfigHdr; + BOOLEAN Result; + + ASSERT (ConfigHdr != NULL); + + // + // Use Guid and Name to generate a string + // + CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL); + if (CompareConfigHdr == NULL) { + return FALSE; + } + + Result = TRUE; + if (Guid != NULL) { + // + // Compare GUID value strings + // + Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME="); + } + + if (Result && Name != NULL) { + // + // Compare NAME value strings + // + Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH="); + } + + // + // Free the string + // + FreePool (CompareConfigHdr); + + return Result; +} + +/** + Retrieves uncommited data from the Form Browser and converts it to a binary + buffer. + + @param[in] VariableName Pointer to a Null-terminated Unicode string. This + is an optional parameter that may be NULL. + @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional + parameter that may be NULL. + @param[in] BufferSize Length in bytes of buffer to hold retrived data. + @param[out] Block Buffer of data to be updated. + + @retval FALSE The uncommitted data could not be retrieved. + @retval TRUE The uncommitted data was retrieved. + +**/ +BOOLEAN +EFIAPI +HiiGetBrowserData ( + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName, OPTIONAL + IN UINTN BlockSize, + OUT UINT8 *Block + ) +{ + EFI_STRING ResultsData; + UINTN Size; + EFI_STRING ConfigResp; + EFI_STATUS Status; + CHAR16 *Progress; + + // + // Retrieve the results data from the Browser Callback + // + ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL); + if (ResultsData == NULL) { + return FALSE; + } + + // + // Construct mConfigHdrTemplate L'&' ResultsData L'\0' + // + Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16); + Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16); + ConfigResp = AllocateZeroPool (Size); + UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData); + + // + // Free the allocated buffer + // + FreePool (ResultsData); + if (ConfigResp == NULL) { + return FALSE; + } + + // + // Convert to a buffer + // + Status = gHiiConfigRouting->ConfigToBlock ( + gHiiConfigRouting, + ConfigResp, + Block, + &BlockSize, + &Progress + ); + // + // Free the allocated buffer + // + FreePool (ConfigResp); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + return TRUE; +} + +/** + Updates uncommitted data in the Form Browser. + + If Buffer is NULL, then ASSERT(). + + @param[in] VariableName Pointer to a Null-terminated Unicode string. This + is an optional parameter that may be NULL. + @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional + parameter that may be NULL. + @param[in] BufferSize Length, in bytes, of Buffer. + @param[in] Buffer Buffer of data to commit. + @param[in] RequestElement An optional field to specify which part of the + buffer data will be send back to Browser. If NULL, + the whole buffer of data will be committed to + Browser. + ::= &OFFSET=&WIDTH=* + + @retval FALSE The uncommitted data could not be updated. + @retval TRUE The uncommitted data was updated. + +**/ +BOOLEAN +EFIAPI +HiiSetBrowserData ( + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName, OPTIONAL + IN UINTN BufferSize, + IN CONST UINT8 *Buffer, + IN CONST CHAR16 *RequestElement OPTIONAL + ) +{ + UINTN Size; + EFI_STRING ConfigRequest; + EFI_STRING ConfigResp; + EFI_STRING ResultsData; + + ASSERT (Buffer != NULL); + + // + // Construct + // + if (RequestElement == NULL) { + // + // Allocate and fill a buffer large enough to hold the template + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator + // + Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize); + } else { + // + // Allocate and fill a buffer large enough to hold the template + // followed by followed by a Null-terminator + // + Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16); + Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement); + } + if (ConfigRequest == NULL) { + return FALSE; + } + + // + // Convert to + // + ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize); + FreePool (ConfigRequest); + if (ConfigResp == NULL) { + return FALSE; + } + + // + // Set data in the uncommitted browser state information + // + ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1); + FreePool (ConfigResp); + + return (BOOLEAN)(ResultsData != NULL); +} + +///////////////////////////////////////// +///////////////////////////////////////// +/// IFR Functions +///////////////////////////////////////// +///////////////////////////////////////// + +#define HII_LIB_OPCODE_ALLOCATION_SIZE 0x200 + +typedef struct { + UINT8 *Buffer; + UINTN BufferSize; + UINTN Position; +} HII_LIB_OPCODE_BUFFER; + +/// +/// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes +/// +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = { + 1, // EFI_IFR_TYPE_NUM_SIZE_8 + 2, // EFI_IFR_TYPE_NUM_SIZE_16 + 4, // EFI_IFR_TYPE_NUM_SIZE_32 + 8, // EFI_IFR_TYPE_NUM_SIZE_64 + 1, // EFI_IFR_TYPE_BOOLEAN + 3, // EFI_IFR_TYPE_TIME + 4, // EFI_IFR_TYPE_DATE + 2 // EFI_IFR_TYPE_STRING +}; + +/** + Allocates and returns a new OpCode Handle. OpCode Handles must be freed with + HiiFreeOpCodeHandle(). + + @retval NULL There are not enough resources to allocate a new OpCode Handle. + @retval Other A new OpCode handle. + +**/ +VOID * +EFIAPI +HiiAllocateOpCodeHandle ( + VOID + ) +{ + HII_LIB_OPCODE_BUFFER *OpCodeBuffer; + + OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER)); + if (OpCodeBuffer == NULL) { + return NULL; + } + OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE); + if (OpCodeBuffer->Buffer == NULL) { + FreePool (OpCodeBuffer); + return NULL; + } + OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE; + OpCodeBuffer->Position = 0; + return (VOID *)OpCodeBuffer; +} + +/** + Frees an OpCode Handle that was peviously allocated with HiiAllocateOpCodeHandle(). + When an OpCode Handle is freed, all of the opcodes associated with the OpCode + Handle are also freed. + + If OpCodeHandle is NULL, then ASSERT(). + +**/ +VOID +EFIAPI +HiiFreeOpCodeHandle ( + VOID *OpCodeHandle + ) +{ + HII_LIB_OPCODE_BUFFER *OpCodeBuffer; + + ASSERT (OpCodeHandle != NULL); + + OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle; + if (OpCodeBuffer->Buffer != NULL) { + FreePool (OpCodeBuffer->Buffer); + } + FreePool (OpCodeBuffer); +} + +UINTN +EFIAPI +InternalHiiOpCodeHandlePosition ( + IN VOID *OpCodeHandle + ) +{ + return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Position; +} + +UINT8 * +EFIAPI +InternalHiiOpCodeHandleBuffer ( + IN VOID *OpCodeHandle + ) +{ + return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Buffer; +} + +UINT8 * +EFIAPI +InternalHiiGrowOpCodeHandle ( + VOID *OpCodeHandle, + UINTN Size + ) +{ + HII_LIB_OPCODE_BUFFER *OpCodeBuffer; + UINT8 *Buffer; + + ASSERT (OpCodeHandle != NULL); + + OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle; + if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) { + Buffer = ReallocatePool ( + OpCodeBuffer->BufferSize, + OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE), + OpCodeBuffer->Buffer + ); + if (Buffer == NULL) { + return NULL; + } + OpCodeBuffer->Buffer = Buffer; + OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE); + } + Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position; + OpCodeBuffer->Position += Size; + return Buffer; +} + +UINT8 * +EFIAPI +InternalHiiCreateOpCodeExtended ( + IN VOID *OpCodeHandle, + IN VOID *OpCodeTemplate, + IN UINT8 OpCode, + IN UINTN OpCodeSize, + IN UINTN ExtensionSize, + IN UINT8 Scope + ) +{ + EFI_IFR_OP_HEADER *Header; + UINT8 *Buffer; + + ASSERT (OpCodeTemplate != NULL); + ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F); + + Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate; + Header->OpCode = OpCode; + Header->Scope = Scope; + Header->Length = (UINT8)(OpCodeSize + ExtensionSize); + Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length); + return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize); +} + +UINT8 * +EFIAPI +InternalHiiCreateOpCode ( + IN VOID *OpCodeHandle, + IN VOID *OpCodeTemplate, + IN UINT8 OpCode, + IN UINTN OpCodeSize + ) +{ + return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0); +} + +/** + Append raw opcodes to an OpCodeHandle. + + If OpCodeHandle is NULL, then ASSERT(). + If RawBuffer is NULL, then ASSERT(); + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] RawBuffer Buffer of opcodes to append. + @param[in] RawBufferSize The size, in bytes, of Buffer. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the appended opcodes. + +**/ +UINT8 * +EFIAPI +HiiCreateRawOpCodes ( + IN VOID *OpCodeHandle, + IN UINT8 *RawBuffer, + IN UINTN RawBufferSize + ) +{ + UINT8 *Buffer; + + ASSERT (RawBuffer != NULL); + + Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize); + return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize); +} + +/** + Append opcodes from one OpCode Handle to another OpCode handle. + + If OpCodeHandle is NULL, then ASSERT(). + If RawOpCodeHandle is NULL, then ASSERT(); + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] RawOpCodeHandle Handle to the buffer of opcodes. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the appended opcodes. +**/ +UINT8 * +EFIAPI +InternalHiiAppendOpCodes ( + IN VOID *OpCodeHandle, + IN VOID *RawOpCodeHandle + ) +{ + HII_LIB_OPCODE_BUFFER *RawOpCodeBuffer; + + ASSERT (RawOpCodeHandle != NULL); + + RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle; + return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position); +} + +/** + Create EFI_IFR_END_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateEndOpCode ( + IN VOID *OpCodeHandle + ) +{ + EFI_IFR_END OpCode; + + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode)); +} + +/** + Create EFI_IFR_ONE_OF_OPTION_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If Type is invalid, then ASSERT(). + If Flags is invalid, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] StringId StringId for the option + @param[in] Flags Flags for the option + @param[in] Type Type for the option + @param[in] Value Value for the option + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateOneOfOptionOpCode ( + IN VOID *OpCodeHandle, + IN UINT16 StringId, + IN UINT8 Flags, + IN UINT8 Type, + IN UINT64 Value + ) +{ + EFI_IFR_ONE_OF_OPTION OpCode; + + ASSERT (Type < EFI_IFR_TYPE_OTHER); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Option = StringId; + OpCode.Flags = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG)); + OpCode.Type = Type; + CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]); + + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, sizeof (OpCode)); +} + +/** + Create EFI_IFR_DEFAULT_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If Type is invalid, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] DefaultId DefaultId for the default + @param[in] Type Type for the default + @param[in] Value Value for the default + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateDefaultOpCode ( + IN VOID *OpCodeHandle, + IN UINT16 DefaultId, + IN UINT8 Type, + IN UINT64 Value + ) +{ + EFI_IFR_DEFAULT OpCode; + + ASSERT (Type < EFI_IFR_TYPE_OTHER); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Type = Type; + OpCode.DefaultId = DefaultId; + CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]); + + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, sizeof (OpCode)); +} + +/** + Create EFI_IFR_GUID opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If Guid is NULL, then ASSERT(). + If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] Guid Pointer to EFI_GUID of this guided opcode. + @param[in] GuidOpCode Pointer to an EFI_IFR_GUID opcode. This is an + optional parameter that may be NULL. If this + parameter is NULL, then the GUID extension + region of the created opcode is filled with zeros. + If this parameter is not NULL, then the GUID + extension region of GuidData will be copied to + the GUID extension region of the created opcode. + @param[in] OpCodeSize The size, in bytes, of created opcode. This value + must be >= sizeof(EFI_IFR_GUID). + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateGuidOpCode ( + IN VOID *OpCodeHandle, + IN CONST EFI_GUID *Guid, + IN CONST VOID *GuidOpCode, OPTIONAL + IN UINTN OpCodeSize + ) +{ + EFI_IFR_GUID OpCode; + EFI_IFR_GUID *OpCodePointer; + + ASSERT (Guid != NULL); + ASSERT (OpCodeSize >= sizeof (OpCode)); + + ZeroMem (&OpCode, sizeof (OpCode)); + CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid); + + OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended ( + OpCodeHandle, + &OpCode, + EFI_IFR_GUID_OP, + sizeof (OpCode), + OpCodeSize - sizeof (OpCode), + 0 + ); + if (OpCodePointer != NULL && GuidOpCode != NULL) { + CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode)); + } + return (UINT8 *)OpCodePointer; +} + +/** + Create EFI_IFR_ACTION_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in QuestionFlags, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] QuestionId Question ID + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] QuestionFlags Flags in Question Header + @param[in] QuestionConfig String ID for configuration + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateActionOpCode ( + IN VOID *OpCodeHandle, + IN EFI_QUESTION_ID QuestionId, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN EFI_STRING_ID QuestionConfig + ) +{ + EFI_IFR_ACTION OpCode; + + ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Question.QuestionId = QuestionId; + OpCode.Question.Header.Prompt = Prompt; + OpCode.Question.Header.Help = Help; + OpCode.Question.Flags = QuestionFlags; + OpCode.QuestionConfig = QuestionConfig; + + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode)); +} + +/** + Create EFI_IFR_SUBTITLE_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in Flags, then ASSERT(). + If Scope > 1, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] Flags Subtitle opcode flags + @param[in] Scope 1 if this opcpde is the beginning of a new scope. + 0 if this opcode is within the current scope. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateSubTitleOpCode ( + IN VOID *OpCodeHandle, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 Flags, + IN UINT8 Scope + ) +{ + EFI_IFR_SUBTITLE OpCode; + + ASSERT (Scope <= 1); + ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Statement.Prompt = Prompt; + OpCode.Statement.Help = Help; + OpCode.Flags = Flags; + + return InternalHiiCreateOpCodeExtended ( + OpCodeHandle, + &OpCode, + EFI_IFR_SUBTITLE_OP, + sizeof (OpCode), + 0, + Scope + ); +} + +/** + Create EFI_IFR_REF_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in QuestionFlags, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] FormId Destination Form ID + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] QuestionFlags Flags in Question Header + @param[in] QuestionId Question ID + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateGotoOpCode ( + IN VOID *OpCodeHandle, + IN EFI_FORM_ID FormId, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN EFI_QUESTION_ID QuestionId + ) +{ + EFI_IFR_REF OpCode; + + ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Question.Header.Prompt = Prompt; + OpCode.Question.Header.Help = Help; + OpCode.Question.QuestionId = QuestionId; + OpCode.Question.Flags = QuestionFlags; + OpCode.FormId = FormId; + + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode)); +} + +/** + Create EFI_IFR_CHECKBOX_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in QuestionFlags, then ASSERT(). + If any reserved bits are set in CheckBoxFlags, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] QuestionId Question ID + @param[in] VarStoreId Storage ID + @param[in] VarOffset Offset in Storage + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] QuestionFlags Flags in Question Header + @param[in] CheckBoxFlags Flags for checkbox opcode + @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This + is an optional parameter that may be NULL. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateCheckBoxOpCode ( + IN VOID *OpCodeHandle, + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 CheckBoxFlags, + IN VOID *DefaultsOpCodeHandle OPTIONAL + ) +{ + EFI_IFR_CHECKBOX OpCode; + UINTN Position; + + ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Question.QuestionId = QuestionId; + OpCode.Question.VarStoreId = VarStoreId; + OpCode.Question.VarStoreInfo.VarOffset = VarOffset; + OpCode.Question.Header.Prompt = Prompt; + OpCode.Question.Header.Help = Help; + OpCode.Question.Flags = QuestionFlags; + OpCode.Flags = CheckBoxFlags; + + if (DefaultsOpCodeHandle == NULL) { + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode)); + } + + Position = InternalHiiOpCodeHandlePosition (OpCodeHandle); + InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1); + InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle); + HiiCreateEndOpCode (OpCodeHandle); + return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position; +} + +/** + Create EFI_IFR_NUMERIC_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in QuestionFlags, then ASSERT(). + If any reserved bits are set in NumericFlags, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] QuestionId Question ID + @param[in] VarStoreId Storage ID + @param[in] VarOffset Offset in Storage + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] QuestionFlags Flags in Question Header + @param[in] NumericFlags Flags for numeric opcode + @param[in] Minimum Numeric minimum value + @param[in] Maximum Numeric maximum value + @param[in] Step Numeric step for edit + @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This + is an optional parameter that may be NULL. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateNumericOpCode ( + IN VOID *OpCodeHandle, + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 NumericFlags, + IN UINT64 Minimum, + IN UINT64 Maximum, + IN UINT64 Step, + IN VOID *DefaultsOpCodeHandle OPTIONAL + ) +{ + EFI_IFR_NUMERIC OpCode; + UINTN Position; + + ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Question.QuestionId = QuestionId; + OpCode.Question.VarStoreId = VarStoreId; + OpCode.Question.VarStoreInfo.VarOffset = VarOffset; + OpCode.Question.Header.Prompt = Prompt; + OpCode.Question.Header.Help = Help; + OpCode.Question.Flags = QuestionFlags; + OpCode.Flags = NumericFlags; + + switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + OpCode.data.u8.MinValue = (UINT8)Minimum; + OpCode.data.u8.MaxValue = (UINT8)Maximum; + OpCode.data.u8.Step = (UINT8)Step; + break; + + case EFI_IFR_NUMERIC_SIZE_2: + OpCode.data.u16.MinValue = (UINT16)Minimum; + OpCode.data.u16.MaxValue = (UINT16)Maximum; + OpCode.data.u16.Step = (UINT16)Step; + break; + + case EFI_IFR_NUMERIC_SIZE_4: + OpCode.data.u32.MinValue = (UINT32)Minimum; + OpCode.data.u32.MaxValue = (UINT32)Maximum; + OpCode.data.u32.Step = (UINT32)Step; + break; + + case EFI_IFR_NUMERIC_SIZE_8: + OpCode.data.u64.MinValue = Minimum; + OpCode.data.u64.MaxValue = Maximum; + OpCode.data.u64.Step = Step; + break; + } + + if (DefaultsOpCodeHandle == NULL) { + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, sizeof (OpCode)); + } + + Position = InternalHiiOpCodeHandlePosition (OpCodeHandle); + InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, sizeof (OpCode), 0, 1); + InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle); + HiiCreateEndOpCode (OpCodeHandle); + return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position; +} + +/** + Create EFI_IFR_STRING_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in QuestionFlags, then ASSERT(). + If any reserved bits are set in StringFlags, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] QuestionId Question ID + @param[in] VarStoreId Storage ID + @param[in] VarOffset Offset in Storage + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] QuestionFlags Flags in Question Header + @param[in] StringFlags Flags for string opcode + @param[in] MinSize String minimum length + @param[in] MaxSize String maximum length + @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This + is an optional parameter that may be NULL. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateStringOpCode ( + IN VOID *OpCodeHandle, + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 StringFlags, + IN UINT8 MinSize, + IN UINT8 MaxSize, + IN VOID *DefaultsOpCodeHandle OPTIONAL + ) +{ + EFI_IFR_STRING OpCode; + UINTN Position; + + ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Question.Header.Prompt = Prompt; + OpCode.Question.Header.Help = Help; + OpCode.Question.QuestionId = QuestionId; + OpCode.Question.VarStoreId = VarStoreId; + OpCode.Question.VarStoreInfo.VarOffset = VarOffset; + OpCode.Question.Flags = QuestionFlags; + OpCode.MinSize = MinSize; + OpCode.MaxSize = MaxSize; + OpCode.Flags = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE); + + if (DefaultsOpCodeHandle == NULL) { + return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode)); + } + + Position = InternalHiiOpCodeHandlePosition (OpCodeHandle); + InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1); + InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle); + HiiCreateEndOpCode (OpCodeHandle); + return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position; +} + +/** + Create EFI_IFR_ONE_OF_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in QuestionFlags, then ASSERT(). + If any reserved bits are set in OneOfFlags, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] QuestionId Question ID + @param[in] VarStoreId Storage ID + @param[in] VarOffset Offset in Storage + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] QuestionFlags Flags in Question Header + @param[in] OneOfFlags Flags for oneof opcode + @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes. + @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This + is an optional parameter that may be NULL. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateOneOfOpCode ( + IN VOID *OpCodeHandle, + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 OneOfFlags, + IN VOID *OptionsOpCodeHandle, + IN VOID *DefaultsOpCodeHandle OPTIONAL + ) +{ + EFI_IFR_ONE_OF OpCode; + UINTN Position; + + ASSERT (OptionsOpCodeHandle != NULL); + ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Question.Header.Prompt = Prompt; + OpCode.Question.Header.Help = Help; + OpCode.Question.QuestionId = QuestionId; + OpCode.Question.VarStoreId = VarStoreId; + OpCode.Question.VarStoreInfo.VarOffset = VarOffset; + OpCode.Question.Flags = QuestionFlags; + OpCode.Flags = OneOfFlags; + + Position = InternalHiiOpCodeHandlePosition (OpCodeHandle); + InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, sizeof (OpCode), 0, 1); + InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle); + if (DefaultsOpCodeHandle != NULL) { + InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle); + } + HiiCreateEndOpCode (OpCodeHandle); + return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position; +} + +/** + Create EFI_IFR_ORDERED_LIST_OP opcode. + + If OpCodeHandle is NULL, then ASSERT(). + If any reserved bits are set in QuestionFlags, then ASSERT(). + If any reserved bits are set in OrderedListFlags, then ASSERT(). + + @param[in] OpCodeHandle Handle to the buffer of opcodes. + @param[in] QuestionId Question ID + @param[in] VarStoreId Storage ID + @param[in] VarOffset Offset in Storage + @param[in] Prompt String ID for Prompt + @param[in] Help String ID for Help + @param[in] QuestionFlags Flags in Question Header + @param[in] OrderedListFlags Flags for ordered list opcode + @param[in] DataType Type for option value + @param[in] MaxContainers Maximum count for options in this ordered list + @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes. + @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This + is an optional parameter that may be NULL. + + @retval NULL There is not enough space left in Buffer to add the opcode. + @retval Other A pointer to the created opcode. + +**/ +UINT8 * +EFIAPI +HiiCreateOrderedListOpCode ( + IN VOID *OpCodeHandle, + IN EFI_QUESTION_ID QuestionId, + IN EFI_VARSTORE_ID VarStoreId, + IN UINT16 VarOffset, + IN EFI_STRING_ID Prompt, + IN EFI_STRING_ID Help, + IN UINT8 QuestionFlags, + IN UINT8 OrderedListFlags, + IN UINT8 DataType, + IN UINT8 MaxContainers, + IN VOID *OptionsOpCodeHandle, + IN VOID *DefaultsOpCodeHandle OPTIONAL + ) +{ + EFI_IFR_ORDERED_LIST OpCode; + UINTN Position; + + ASSERT (OptionsOpCodeHandle != NULL); + ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0); + + ZeroMem (&OpCode, sizeof (OpCode)); + OpCode.Question.Header.Prompt = Prompt; + OpCode.Question.Header.Help = Help; + OpCode.Question.QuestionId = QuestionId; + OpCode.Question.VarStoreId = VarStoreId; + OpCode.Question.VarStoreInfo.VarOffset = VarOffset; + OpCode.Question.Flags = QuestionFlags; + OpCode.MaxContainers = MaxContainers; + OpCode.Flags = OrderedListFlags; + + Position = InternalHiiOpCodeHandlePosition (OpCodeHandle); + InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1); + InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle); + if (DefaultsOpCodeHandle != NULL) { + InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle); + } + HiiCreateEndOpCode (OpCodeHandle); + return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position; +} + +/** + This is the internal worker function to update the data in + a form specified by FormSetGuid, FormId and Label. + + @param FormSetGuid The optional Formset GUID. + @param FormId The Form ID. + @param Package The package header. + + @param TempPacakge The resultant package. + + @retval EFI_SUCCESS The function completes successfully. + +**/ +EFI_STATUS +EFIAPI +InternalHiiUpdateFormPackageData ( + IN EFI_GUID *FormSetGuid, OPTIONAL + IN EFI_FORM_ID FormId, + IN EFI_HII_PACKAGE_HEADER *Package, + IN HII_LIB_OPCODE_BUFFER *OpCodeBufferStart, + IN HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd, OPTIONAL + OUT EFI_HII_PACKAGE_HEADER *TempPackage + ) +{ + UINTN AddSize; + UINT8 *BufferPos; + EFI_HII_PACKAGE_HEADER PackageHeader; + UINTN Offset; + EFI_IFR_OP_HEADER *IfrOpHdr; + EFI_IFR_OP_HEADER *UpdateIfrOpHdr; + BOOLEAN GetFormSet; + BOOLEAN GetForm; + BOOLEAN Updated; + UINTN UpdatePackageLength; + + CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER); + BufferPos = (UINT8 *) (TempPackage + 1); + + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER)); + Offset = sizeof (EFI_HII_PACKAGE_HEADER); + GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE); + GetForm = FALSE; + Updated = FALSE; + + while (Offset < PackageHeader.Length) { + CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length); + BufferPos += IfrOpHdr->Length; + UpdatePackageLength += IfrOpHdr->Length; + + // + // Find the matched FormSet and Form + // + if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) { + if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) { + GetFormSet = TRUE; + } else { + GetFormSet = FALSE; + } + } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP) { + if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) { + GetForm = TRUE; + } else { + GetForm = FALSE; + } + } + + // + // The matched Form is found, and Update data in this form + // + if (GetFormSet && GetForm) { + UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer; + if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \ + (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) { + // + // Remove the original data when End OpCode buffer exist. + // + if (OpCodeBufferEnd != NULL) { + Offset += IfrOpHdr->Length; + IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length); + UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer; + while (Offset < PackageHeader.Length) { + // + // Search the matched end opcode + // + if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \ + (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) { + break; + } + // + // Go to the next Op-Code + // + Offset += IfrOpHdr->Length; + IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length); + } + + if (Offset >= PackageHeader.Length) { + // + // The end opcode is not found. + // + return EFI_NOT_FOUND; + } + } + + // + // Insert the updated data + // + AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length; + CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize); + BufferPos += OpCodeBufferStart->Position - AddSize; + UpdatePackageLength += OpCodeBufferStart->Position - AddSize; + + if (OpCodeBufferEnd != NULL) { + // + // Add the end opcode + // + CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length); + BufferPos += IfrOpHdr->Length; + UpdatePackageLength += IfrOpHdr->Length; + } + + // + // Copy the left package data. + // + Offset += IfrOpHdr->Length; + CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset); + UpdatePackageLength += PackageHeader.Length - Offset; + + // + // Set update flag + // + Updated = TRUE; + break; + } + } + + // + // Go to the next Op-Code + // + Offset += IfrOpHdr->Length; + IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length); + } + + if (!Updated) { + // + // The updated opcode buffer is not found. + // + return EFI_NOT_FOUND; + } + // + // Update the package length. + // + PackageHeader.Length = (UINT32) UpdatePackageLength; + CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER)); + + return EFI_SUCCESS; +} + +/** + This function updates a form that has previously been registered with the HII + Database. This function will perform at most one update operation. + + The form to update is specified by Handle, FormSetGuid, and FormId. Binary + comparisons of IFR opcodes are performed from the beginning of the form being + updated until an IFR opcode is found that exactly matches the first IFR opcode + specifed by StartOpCodeHandle. The following rules are used to determine if + an insert, replace, or delete operation is performed. + + 1) If no matches are found, then NULL is returned. + 2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes + from StartOpcodeHandle except the first opcode are inserted immediately after + the matching IFR opcode in the form beng updated. + 3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made + from the matching IFR opcode until an IFR opcode exatly matches the first + IFR opcode specified by EndOpCodeHandle. If no match is found for the first + IFR opcode specified by EndOpCodeHandle, then NULL is returned. If a match + is found, then all of the IFR opcodes between the start match and the end + match are deleted from the form being updated and all of the IFR opcodes + from StartOpcodeHandle except the first opcode are inserted immediately after + the matching start IFR opcode. If StartOpCcodeHandle only contains one + IFR instruction, then the result of ths operation will delete all of the IFR + opcodes between the start end matches. + + If HiiHandle is NULL, then ASSERT(). + If StartOpCodeHandle is NULL, then ASSERT(). + + @param[in] HiiHandle The HII Handle of the form to update. + @param[in] FormSetGuid The Formset GUID of the form to update. This + is an optional parameter that may be NULL. + If it is NULL, all FormSet will be updated. + @param[in] FormId The ID of the form to update. + @param[in] StartOpCodeHandle An OpCode Handle that contains the set of IFR + opcodes to be inserted or replaced in the form. + The first IFR instruction in StartOpCodeHandle + is used to find matching IFR opcode in the + form. + @param[in] EndOpCodeHandle An OpCcode Handle that contains the IFR opcode + that marks the end of a replace operation in + the form. This is an optional parameter that + may be NULL. If it is NULL, then an the IFR + opcodes specified by StartOpCodeHandle are + inserted into the form. + + @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated. + @retval EFI_NOT_FOUND The following cases will return EFI_NOT_FOUND. + 1) The form specified by HiiHandle, FormSetGuid, + and FormId could not be found in the HII Database. + 2) No IFR opcodes in the target form match the first + IFR opcode in StartOpCodeHandle. + 3) EndOpCOde is not NULL, and no IFR opcodes in the + target form following a matching start opcode match + the first IFR opcode in EndOpCodeHandle. + @retval EFI_SUCCESS The matched form is updated by StartOpcode. + +**/ +EFI_STATUS +EFIAPI +HiiUpdateForm ( + IN EFI_HII_HANDLE HiiHandle, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN EFI_FORM_ID FormId, + IN VOID *StartOpcodeHandle, + IN VOID *EndOpcodeHandle OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINT32 PackageListLength; + UINT32 Offset; + EFI_HII_PACKAGE_LIST_HEADER *UpdatePackageList; + UINTN BufferSize; + UINT8 *UpdateBufferPos; + EFI_HII_PACKAGE_HEADER *Package; + EFI_HII_PACKAGE_HEADER *TempPacakge; + EFI_HII_PACKAGE_HEADER PackageHeader; + BOOLEAN Updated; + HII_LIB_OPCODE_BUFFER *OpCodeBufferStart; + HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd; + + // + // Input update data can't be NULL. + // + ASSERT (HiiHandle != NULL); + ASSERT (StartOpcodeHandle != NULL); + UpdatePackageList = NULL; + TempPacakge = NULL; + HiiPackageList = NULL; + + // + // Restrive buffer data from Opcode Handle + // + OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpcodeHandle; + OpCodeBufferEnd = (HII_LIB_OPCODE_BUFFER *) EndOpcodeHandle; + + // + // Get the orginal package list + // + BufferSize = 0; + HiiPackageList = NULL; + Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList); + // + // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0. + // + if (Status != EFI_BUFFER_TOO_SMALL) { + return Status; + } + + HiiPackageList = AllocatePool (BufferSize); + if (HiiPackageList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + + Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // Calculate and allocate space for retrieval of IFR data + // + BufferSize += OpCodeBufferStart->Position; + UpdatePackageList = AllocateZeroPool (BufferSize); + if (UpdatePackageList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + + // + // Allocate temp buffer to store the temp updated package buffer + // + TempPacakge = AllocateZeroPool (BufferSize); + if (TempPacakge == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + + UpdateBufferPos = (UINT8 *) UpdatePackageList; + + // + // Copy the package list header + // + CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER)); + UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER); + + // + // Go through each package to find the matched pacakge and update one by one + // + Updated = FALSE; + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength); + while (Offset < PackageListLength) { + Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset); + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + Offset += Package->Length; + + if (Package->Type == EFI_HII_PACKAGE_FORMS) { + // + // Check this package is the matched package. + // + Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPacakge); + // + // The matched package is found. Its pacakge buffer will be updated by the input new data. + // + if (!EFI_ERROR(Status)) { + // + // Set Update Flag + // + Updated = TRUE; + // + // Add updated package buffer + // + Package = TempPacakge; + } + } + + // + // Add pacakge buffer + // + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + CopyMem (UpdateBufferPos, Package, PackageHeader.Length); + UpdateBufferPos += PackageHeader.Length; + } + + if (Updated) { + // + // Update package list length + // + BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList; + WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize); + + // + // Update Pacakge to show form + // + Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList); + } else { + // + // Not matched form is found and updated. + // + Status = EFI_NOT_FOUND; + } + +Finish: + if (HiiPackageList != NULL) { + FreePool (HiiPackageList); + } + + if (UpdatePackageList != NULL) { + FreePool (UpdatePackageList); + } + + if (TempPacakge != NULL) { + FreePool (TempPacakge); + } + + return Status; +}