X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=EdkCompatibilityPkg%2FCompatibility%2FFrameworkHiiToUefiHiiThunk%2FConfigAccess.c;h=edbc34a3e49f4cdc2eb4575ec9fb9cdad7742887;hb=98b16b9dad5c90b59d4b39f2af904cc4bfb3e6b8;hp=c537a47b1ce9c5c43277a6f9bfcb701191d91b17;hpb=133a9dfb54bee02bf76aeb158da42594ffbc8a73;p=mirror_edk2.git diff --git a/EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c b/EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c index c537a47b1c..edbc34a3e4 100644 --- a/EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c +++ b/EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c @@ -1,7 +1,7 @@ /**@file - This file contains functions related to Config Access Protocols installed by - by HII Thunk Modules which is used to thunk UEFI Config Access Callback to - Framework HII Callback. + This file implements functions related to Config Access Protocols installed by + by HII Thunk Modules. These Config access Protocols are used to thunk UEFI Config + Access Callback to Framework HII Callback and EFI Variable Set/Get operations. Copyright (c) 2008, Intel Corporation All rights reserved. This program and the accompanying materials @@ -15,8 +15,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "HiiDatabase.h" +#include "UefiIfrParser.h" -BOOLEAN mHiiPackageListUpdated; +BOOLEAN mHiiPackageListUpdated = FALSE; CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = { CONFIG_ACCESS_PRIVATE_SIGNATURE, @@ -26,154 +27,157 @@ CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = { ThunkCallback }, //ConfigAccessProtocol NULL, //FormCallbackProtocol - {NULL, NULL}, //ConfigAccessStorageListHead NULL }; /** - Find and return the pointer to Package Header of the Form package - in the Framework Package List. The Framework Package List is created - by a module calling the Framework HII interface. - The Framwork Package List contains package data - generated by Intel's UEFI VFR Compiler and String gather tool. The data format - of the package data is defined by TIANO_AUTOGEN_PACKAGES_HEADER. - - If the package list contains other type of packages such as KEYBOARD_LAYOUT, - FONTS and IMAGES, the ASSERT. This is to make sure the caller is a - Framework Module which does not include packages introduced by UEFI Specification - or packages that is not supported by Thunk layer. + Get the first EFI_IFR_VARSTORE from the FormSet. - @param Packages The Framework Package List + @param FormSet The Form Set. - @retval EFI_HII_PACKAGE_HEADER* Return the Package Header of Form Package. - @retval NULL If no Form Package is found. + @retval FORMSET_STORAGE * Return the first EFI_IFR_VARSTORE. + @retval NULL If the Form Set does not have EFI_IFR_VARSTORE. **/ -EFI_HII_PACKAGE_HEADER * -GetIfrFormSet ( - IN CONST EFI_HII_PACKAGES *Packages +FORMSET_STORAGE * +GetFirstStorageOfFormSet ( + IN CONST FORM_BROWSER_FORMSET * FormSet + ) +{ + LIST_ENTRY *StorageList; + FORMSET_STORAGE *Storage; + + StorageList = GetFirstNode (&FormSet->StorageListHead); + + if (!IsNull (&FormSet->StorageListHead, StorageList)) { + Storage = FORMSET_STORAGE_FROM_LINK (StorageList); + return Storage; + } + + return NULL; +} + +/** + Get the EFI_IFR_VARSTORE where the Question's value is stored. + + @param FormSet The Form Set. + + @retval FORMSET_STORAGE * The EFI_IFR_VARSTORE where the Question's value is stored. + @retval NULL If the Form Set does not have EFI_IFR_VARSTORE. +**/ +FORMSET_STORAGE * +GetStorageFromQuestionId ( + IN CONST FORM_BROWSER_FORMSET * FormSet, + IN EFI_QUESTION_ID QuestionId ) { - TIANO_AUTOGEN_PACKAGES_HEADER **TianoAutogenPackageHdrArray; - EFI_HII_PACKAGE_HEADER *IfrPackage; - UINTN Index; + LIST_ENTRY *FormList; + LIST_ENTRY *StatementList; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Statement; + + FormList = GetFirstNode (&FormSet->FormListHead); + + while (!IsNull (&FormSet->FormListHead, FormList)) { + Form = FORM_BROWSER_FORM_FROM_LINK (FormList); + + StatementList = GetFirstNode (&Form->StatementListHead); + + while (!IsNull (&Form->StatementListHead, StatementList)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (StatementList); + if ((QuestionId == Statement->QuestionId) && (Statement->Storage != NULL)) { + // + // UEFI Question ID is unique in a FormSet. + // + ASSERT (Statement->Storage->Type == EFI_HII_VARSTORE_BUFFER); + return Statement->Storage; + } + StatementList = GetNextNode (&Form->StatementListHead, StatementList); + } - ASSERT (Packages != NULL); + FormList = GetNextNode (&FormSet->FormListHead, FormList); + } + + return NULL; +} - IfrPackage = NULL; +/** + Get the EFI_IFR_VARSTORE based the ID. + + @param FormSet The Form Set. + + @retval FORMSET_STORAGE * The EFI_IFR_VARSTORE with the ID. + @retval NULL If the Form Set does not have EFI_IFR_VARSTORE with such ID. +**/ +FORMSET_STORAGE * +GetStorageFromVarStoreId ( + IN CONST FORM_BROWSER_FORMSET * FormSet, + IN EFI_VARSTORE_ID VarStoreId + ) +{ + LIST_ENTRY *StorageList; + FORMSET_STORAGE *Storage; - TianoAutogenPackageHdrArray = (TIANO_AUTOGEN_PACKAGES_HEADER **) (((UINT8 *) &Packages->GuidId) + sizeof (Packages->GuidId)); - for (Index = 0; Index < Packages->NumberOfPackages; Index++) { - // - // BugBug: The current UEFI HII build tool generate a binary in the format defined in: - // TIANO_AUTOGEN_PACKAGES_HEADER. We assume that all packages generated in - // this binary is with same package type. So the returned IfrPackNum and StringPackNum - // may not be the exact number of valid package number in the binary generated - // by HII Build tool. - // - switch (TianoAutogenPackageHdrArray[Index]->PackageHeader.Type) { - case EFI_HII_PACKAGE_FORM: - return &TianoAutogenPackageHdrArray[Index]->PackageHeader; - break; + StorageList = GetFirstNode (&FormSet->StorageListHead); - case EFI_HII_PACKAGE_STRINGS: - case EFI_HII_PACKAGE_SIMPLE_FONTS: - break; + while (!IsNull (&FormSet->StorageListHead, StorageList)) { + Storage = FORMSET_STORAGE_FROM_LINK (StorageList); - // - // The following fonts are invalid for a module that using Framework to UEFI thunk layer. - // - case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: - case EFI_HII_PACKAGE_FONTS: - case EFI_HII_PACKAGE_IMAGES: - default: - ASSERT (FALSE); - break; + if (VarStoreId == Storage->VarStoreId) { + return Storage; } - } - return (EFI_HII_PACKAGE_HEADER *) NULL; + StorageList = GetNextNode (&FormSet->StorageListHead, StorageList); + } + + return NULL; } /** - This function scan EFI_IFR_VARSTORE_OP in the Form Package. - It create entries for these VARSTORE found and append the entry - to a Link List. - - If FormSetPackage is not EFI_HII_PACKAGE_FORM, then ASSERT. - If there is no linear buffer storage in this formset, then ASSERT. - - @param FormSetPackage The Form Package header. - @param BufferStorageListHead The link list for the VARSTORE found in the form package. + Get the EFI_IFR_VARSTORE based the string in a + or a string. + + @param FormSet The Form Set. + @param ConfigString The Configuration String which is defined by UEFI HII. - @retval EFI_SUCCESS The function scan the form set and find one or more VARSTOREs. - @retval EFI_OUT_OF_RESOURCES There is not enough memory to complete the function. + @retval FORMSET_STORAGE * The EFI_IFR_VARSTORE where the Question's value is stored. + @retval NULL If the Form Set does not have EFI_IFR_VARSTORE with such ID. **/ -EFI_STATUS -GetBufferStorage ( - IN CONST EFI_HII_PACKAGE_HEADER *FormSetPackage, - OUT LIST_ENTRY *BufferStorageListHead +FORMSET_STORAGE * +GetStorageFromConfigString ( + IN CONST FORM_BROWSER_FORMSET *FormSet, + IN CONST EFI_STRING ConfigString ) { - UINTN OpCodeOffset; - UINTN OpCodeLength; - UINT8 *OpCodeData; - UINT8 Operand; - EFI_IFR_VARSTORE *VarStoreOpCode; - BUFFER_STORAGE_ENTRY *BufferStorage; - - ASSERT (FormSetPackage->Type == EFI_HII_PACKAGE_FORM); - - OpCodeOffset = sizeof (EFI_HII_PACKAGE_HEADER); - // - // Scan all opcode for the FormSet Package for - // EFI_IFR_VARSTORE_OP opcode. - // - while (OpCodeOffset < FormSetPackage->Length) { - OpCodeData = (UINT8 *) FormSetPackage + OpCodeOffset; - - OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; - OpCodeOffset += OpCodeLength; - Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode; - - if (Operand == EFI_IFR_VARSTORE_OP) { - VarStoreOpCode = (EFI_IFR_VARSTORE *)OpCodeData; - BufferStorage = AllocateZeroPool (sizeof (*BufferStorage)); - if (BufferStorage == NULL) { - return EFI_OUT_OF_RESOURCES; - } - // - // Record the attributes: GUID, Name, VarStoreId and Size. - // - CopyMem (&BufferStorage->Guid, &VarStoreOpCode->Guid, sizeof (EFI_GUID)); - - BufferStorage->Name = AllocateZeroPool (AsciiStrSize (VarStoreOpCode->Name) * 2); - AsciiStrToUnicodeStr (VarStoreOpCode->Name, BufferStorage->Name); + LIST_ENTRY *StorageList; + FORMSET_STORAGE *Storage; - BufferStorage->VarStoreId = VarStoreOpCode->VarStoreId; + StorageList = GetFirstNode (&FormSet->StorageListHead); - BufferStorage->Size = VarStoreOpCode->Size; - BufferStorage->Signature = BUFFER_STORAGE_ENTRY_SIGNATURE; + while (!IsNull (&FormSet->StorageListHead, StorageList)) { + Storage = FORMSET_STORAGE_FROM_LINK (StorageList); - InsertTailList (BufferStorageListHead, &BufferStorage->Link); + if (IsConfigHdrMatch (ConfigString, &Storage->Guid, Storage->Name)) { + return Storage; } + + StorageList = GetNextNode (&FormSet->StorageListHead, StorageList); } - return EFI_SUCCESS; + return NULL; } - /** This function installs a EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered by a module using Framework HII Protocol Interfaces. - UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so - that Setup Utility can load the Buffer Storage using this protocol. + UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so + that Setup Utility can load the Buffer Storage using this protocol. - @param Packages The framework package list. - @param ThunkContext The Thunk Layer Handle Mapping Database Entry. + @param Packages The Package List. + @param ThunkContext The Thunk Context. - @retval EFI_SUCCESS The Config Access Protocol is installed successfully. - @retval EFI_OUT_RESOURCE There is not enough memory. + @retval EFI_SUCCESS The Config Access Protocol is installed successfully. + @retval EFI_OUT_RESOURCE There is not enough memory. **/ EFI_STATUS @@ -182,73 +186,42 @@ InstallDefaultConfigAccessProtocol ( IN OUT HII_THUNK_CONTEXT *ThunkContext ) { - EFI_HII_PACKAGE_HEADER *FormSetPackage; EFI_STATUS Status; CONFIG_ACCESS_PRIVATE *ConfigAccessInstance; + ASSERT (ThunkContext->IfrPackageCount != 0); + Status = HiiLibCreateHiiDriverHandle (&ThunkContext->UefiHiiDriverHandle); + ASSERT_EFI_ERROR (Status); + ConfigAccessInstance = AllocateCopyPool ( sizeof (CONFIG_ACCESS_PRIVATE), &gConfigAccessPrivateTempate ); ASSERT (ConfigAccessInstance != NULL); - InitializeListHead (&ConfigAccessInstance->BufferStorageListHead); - - // - // We assume there is only one formset package in each Forms Package - // - FormSetPackage = GetIfrFormSet (Packages); - ASSERT (FormSetPackage != NULL); - - Status = GetBufferStorage (FormSetPackage, &ConfigAccessInstance->BufferStorageListHead); - if (EFI_ERROR (Status)) { - FreePool (ConfigAccessInstance); - ASSERT (FALSE); - return Status; - } - Status = gBS->InstallMultipleProtocolInterfaces ( &ThunkContext->UefiHiiDriverHandle, &gEfiHiiConfigAccessProtocolGuid, &ConfigAccessInstance->ConfigAccessProtocol, NULL ); - // - //BUGBUG: Remove when done. - // ASSERT_EFI_ERROR (Status); - if (EFI_ERROR (Status)) { - FreePool (ConfigAccessInstance); - return Status; - } - ConfigAccessInstance->ThunkContext = ThunkContext; return EFI_SUCCESS; } -VOID -DestroyBufferStorageList ( - IN LIST_ENTRY *ListHead - ) -{ - LIST_ENTRY *Link; - BUFFER_STORAGE_ENTRY *Entry; - - while (!IsListEmpty (ListHead)) { - Link = GetFirstNode (ListHead); - - Entry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link); - - FreePool (Entry->Name); - Link = RemoveEntryList (Link); +/** + This function un-installs the EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered + by a module using Framework HII Protocol Interfaces. - FreePool (Entry); - } -} + ASSERT if no Config Access is found for such pakcage list or failed to uninstall the protocol. + @param ThunkContext The Thunk Context. + +**/ VOID UninstallDefaultConfigAccessProtocol ( IN HII_THUNK_CONTEXT *ThunkContext @@ -256,7 +229,6 @@ UninstallDefaultConfigAccessProtocol ( { EFI_STATUS Status; EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - CONFIG_ACCESS_PRIVATE *ConfigAccessInstance; HiiLibDestroyHiiDriverHandle (ThunkContext->UefiHiiDriverHandle); @@ -265,7 +237,6 @@ UninstallDefaultConfigAccessProtocol ( &gEfiHiiConfigAccessProtocolGuid, (VOID **) &ConfigAccess ); - ASSERT_EFI_ERROR (Status); Status = gBS->UninstallProtocolInterface ( @@ -275,10 +246,6 @@ UninstallDefaultConfigAccessProtocol ( ); ASSERT_EFI_ERROR (Status); - ConfigAccessInstance = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (ConfigAccess); - - DestroyBufferStorageList (&ConfigAccessInstance->BufferStorageListHead); - } @@ -296,7 +263,7 @@ UninstallDefaultConfigAccessProtocol ( **/ EFI_STATUS CallFormCallBack ( - IN BUFFER_STORAGE_ENTRY *BufferStorage, + IN FORMSET_STORAGE *BufferStorage, IN EFI_FORM_CALLBACK_PROTOCOL *FwFormCallBack, OUT VOID **Data, OUT UINTN *DataSize @@ -358,7 +325,7 @@ CallFormCallBack ( EFI_STATUS GetUefiVariable ( - IN BUFFER_STORAGE_ENTRY *BufferStorage, + IN FORMSET_STORAGE *BufferStorage, OUT VOID **Data, OUT UINTN *DataSize ) @@ -432,26 +399,19 @@ ThunkExtractConfig ( { EFI_STATUS Status; CONFIG_ACCESS_PRIVATE *ConfigAccess; - LIST_ENTRY *Link; - BUFFER_STORAGE_ENTRY *BufferStorage; + FORMSET_STORAGE *BufferStorage; VOID *Data; UINTN DataSize; Data = NULL; ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This); - // - // For now, only one var varstore is supported so that we don't need to parse the Configuration string. - // - Link = GetFirstNode (&ConfigAccess->BufferStorageListHead); - if (Link == NULL) { - ASSERT (FALSE); - return EFI_INVALID_PARAMETER; - } - - BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link); + BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Request); if (ConfigAccess->ThunkContext->NvMapOverride == NULL) { + // + // NvMapOverride is not used. Get the Storage data from EFI Variable or Framework Form Callback. + // if (ConfigAccess->FormCallbackProtocol == NULL || ConfigAccess->FormCallbackProtocol->NvRead == NULL) { Status = GetUefiVariable ( @@ -468,6 +428,9 @@ ThunkExtractConfig ( ); } } else { + // + // Use the NvMapOverride. + // DataSize = BufferStorage->Size; Data = AllocateCopyPool (DataSize, ConfigAccess->ThunkContext->NvMapOverride); @@ -489,12 +452,13 @@ ThunkExtractConfig ( ); } - SafeFreePool (Data); + if (Data != NULL) { + FreePool (Data); + } return Status; } /** - This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.RouteConfig so that data can be written to the data storage such as UEFI Variable or module's customized storage exposed by EFI_FRAMEWORK_CALLBACK. @@ -519,9 +483,8 @@ ThunkRouteConfig ( { EFI_STATUS Status; CONFIG_ACCESS_PRIVATE *ConfigAccess; - LIST_ENTRY *Link; - BUFFER_STORAGE_ENTRY *BufferStorage; - UINT8 *Data; + FORMSET_STORAGE *BufferStorage; + VOID *Data; UINTN DataSize; UINTN DataSize2; UINTN LastModifiedByteIndex; @@ -531,16 +494,8 @@ ThunkRouteConfig ( Data = NULL; ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This); - // - // For now, only one var varstore is supported so that we don't need to parse the Configuration string. - // - Link = GetFirstNode (&ConfigAccess->BufferStorageListHead); - if (Link == NULL) { - ASSERT (FALSE); - return EFI_INVALID_PARAMETER; - } + BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Configuration); - BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link); DataSize2 = BufferStorage->Size; if (ConfigAccess->ThunkContext->NvMapOverride == NULL) { DataAllocated = TRUE; @@ -617,6 +572,21 @@ Done: return Status; } +/** + Build the FRAMEWORK_EFI_IFR_DATA_ARRAY which will be used to pass to + EFI_FORM_CALLBACK_PROTOCOL.Callback. Check definition of FRAMEWORK_EFI_IFR_DATA_ARRAY + for details. + + ASSERT if the Question Type is not EFI_IFR_TYPE_NUM_SIZE_* or EFI_IFR_TYPE_STRING. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL + @param QuestionId The Question ID. + @param Type The Question Type. + @param Value The Question Value. + @param NvMapAllocated On output indicates if a buffer is allocated for NvMap. + + @return A pointer to FRAMEWORK_EFI_IFR_DATA_ARRAY. The caller must free this buffer allocated. +**/ FRAMEWORK_EFI_IFR_DATA_ARRAY * CreateIfrDataArray ( IN CONFIG_ACCESS_PRIVATE *ConfigAccess, @@ -629,31 +599,15 @@ CreateIfrDataArray ( FRAMEWORK_EFI_IFR_DATA_ARRAY *IfrDataArray; FRAMEWORK_EFI_IFR_DATA_ENTRY *IfrDataEntry; UINTN BrowserDataSize; - BUFFER_STORAGE_ENTRY *BufferStorageEntry; - LIST_ENTRY *Link; + FORMSET_STORAGE *BufferStorage; EFI_STATUS Status; + UINTN Size; + UINTN StringSize; + EFI_STRING String; - IfrDataArray = AllocateZeroPool (0x100); - ASSERT (IfrDataArray != NULL); - - Link = GetFirstNode (&ConfigAccess->BufferStorageListHead); - ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link)); - - BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link); - BrowserDataSize = BufferStorageEntry->Size; - - if (ConfigAccess->ThunkContext->NvMapOverride == NULL) { - *NvMapAllocated = TRUE; - IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize); - } else { - *NvMapAllocated = FALSE; - IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride; - } - - Status = GetBrowserData (NULL, NULL, &BrowserDataSize, IfrDataArray->NvRamMap); - ASSERT_EFI_ERROR (Status); + *NvMapAllocated = FALSE; - IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1); + String = NULL; switch (Type) { case EFI_IFR_TYPE_NUM_SIZE_8: @@ -661,55 +615,177 @@ CreateIfrDataArray ( case EFI_IFR_TYPE_NUM_SIZE_32: case EFI_IFR_TYPE_NUM_SIZE_64: case EFI_IFR_TYPE_BOOLEAN: - CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value)); + Size = sizeof (*Value); break; + case EFI_IFR_TYPE_STRING: + StringSize = 0; + Status = HiiLibGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, String, &StringSize); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + String = AllocateZeroPool (StringSize); + ASSERT (String != NULL); + + Status = HiiLibGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, String, &StringSize); + ASSERT_EFI_ERROR (Status); + + Size = StringSize; + break; + default: ASSERT (FALSE); + Size = 0; break; } + IfrDataArray = AllocateZeroPool (sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY) + sizeof (FRAMEWORK_EFI_IFR_DATA_ENTRY) + Size); + ASSERT (IfrDataArray != NULL); + + BufferStorage = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId); + + if (BufferStorage == NULL) { + // + // The QuestionId is not associated with a Buffer Storage. + // Try to get the first Buffer Storage then. + // + BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet); + } + + if (BufferStorage != NULL) { + BrowserDataSize = BufferStorage->Size; + + if (ConfigAccess->ThunkContext->NvMapOverride == NULL) { + *NvMapAllocated = TRUE; + IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize); + } else { + *NvMapAllocated = FALSE; + IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride; + } + + Status = GetBrowserData (&BufferStorage->Guid, BufferStorage->Name, &BrowserDataSize, IfrDataArray->NvRamMap); + ASSERT_EFI_ERROR (Status); + + IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1); + + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + case EFI_IFR_TYPE_NUM_SIZE_16: + case EFI_IFR_TYPE_NUM_SIZE_32: + case EFI_IFR_TYPE_NUM_SIZE_64: + case EFI_IFR_TYPE_BOOLEAN: + CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value)); + break; + + case EFI_IFR_TYPE_STRING: + ASSERT (String != NULL); + StrCpy ((CHAR16 *) &IfrDataEntry->Data, String); + FreePool (String); + break; + default: + ASSERT (FALSE); + break; + } + + // + // Need to fiil in the information for the rest of field for FRAMEWORK_EFI_IFR_DATA_ENTRY. + // It seems that no implementation is found to use other fields. Leave them uninitialized for now. + // + //UINT8 OpCode; // Likely a string, numeric, or one-of + //UINT8 Length; // Length of the FRAMEWORK_EFI_IFR_DATA_ENTRY packet + //UINT16 Flags; // Flags settings to determine what behavior is desired from the browser after the callback + //VOID *Data; // The data in the form based on the op-code type - this is not a pointer to the data, the data follows immediately + // If the OpCode is a OneOf or Numeric type - Data is a UINT16 value + // If the OpCode is a String type - Data is a CHAR16[x] type + // If the OpCode is a Checkbox type - Data is a UINT8 value + // If the OpCode is a NV Access type - Data is a FRAMEWORK_EFI_IFR_NV_DATA structure + } + return IfrDataArray; } +/** + If a NvMapOverride is passed in to EFI_FORM_BROWSER_PROTOCOL.SendForm, the Form Browser + needs to be informed when data changed in NvMapOverride. This function will invoke + SetBrowserData () to set internal data of Form Browser. + + @param ConfigAccess The Config Access Private Context. + @param QuestionId The Question Id that invokes the callback. + + +**/ VOID SyncBrowserDataForNvMapOverride ( - IN CONFIG_ACCESS_PRIVATE *ConfigAccess + IN CONST CONFIG_ACCESS_PRIVATE *ConfigAccess, + IN EFI_QUESTION_ID QuestionId ) { - BUFFER_STORAGE_ENTRY *BufferStorageEntry; - LIST_ENTRY *Link; + FORMSET_STORAGE *BufferStorage; EFI_STATUS Status; UINTN BrowserDataSize; if (ConfigAccess->ThunkContext->NvMapOverride != NULL) { + + BufferStorage = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId); + + if (BufferStorage == NULL) { + // + // QuestionId is a statement without Storage. + // 1) It is a Goto. + // + // + BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet); + } + + // + // If NvMapOverride is not NULL, this Form must have at least one Buffer Type Variable Storage. + // + ASSERT (BufferStorage != NULL); - Link = GetFirstNode (&ConfigAccess->BufferStorageListHead); - ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link)); - - BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link); - BrowserDataSize = BufferStorageEntry->Size; + BrowserDataSize = BufferStorage->Size; - Status = SetBrowserData (NULL, NULL, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL); + Status = SetBrowserData (&BufferStorage->Guid, BufferStorage->Name, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL); ASSERT_EFI_ERROR (Status); } } +/** + Free up resource allocated for a FRAMEWORK_EFI_IFR_DATA_ARRAY by CreateIfrDataArray (). + + @param Array The FRAMEWORK_EFI_IFR_DATA_ARRAY allocated. + @param NvMapAllocated If the NvRamMap is allocated for FRAMEWORK_EFI_IFR_DATA_ARRAY. + +**/ VOID DestroyIfrDataArray ( IN FRAMEWORK_EFI_IFR_DATA_ARRAY *Array, IN BOOLEAN NvMapAllocated ) { - if (NvMapAllocated) { - FreePool (Array->NvRamMap); - } + if (Array != NULL) { + if (NvMapAllocated) { + FreePool (Array->NvRamMap); + } - FreePool (Array); + FreePool (Array); + } } - +/** + Get the ONE_OF_OPTION_MAP_ENTRY for a QuestionId that invokes the + EFI_FORM_CALLBACK_PROTOCOL.Callback. The information is needed as + the callback mechanism for EFI_IFR_ONE_OF_OPTION is changed from + EFI_IFR_ONE_OF_OPTION in Framework IFR. Check EFI_IFR_GUID_OPTIONKEY + for detailed information. + + @param ThunkContext The Thunk Context. + @param QuestionId The Question Id. + @param Type The Question Type. + @param Value The One Of Option's value. + + @return The ONE_OF_OPTION_MAP_ENTRY found. + @retval NULL If no entry is found. +**/ ONE_OF_OPTION_MAP_ENTRY * GetOneOfOptionMapEntry ( IN HII_THUNK_CONTEXT *ThunkContext, @@ -722,10 +798,13 @@ GetOneOfOptionMapEntry ( LIST_ENTRY *Link2; ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry; ONE_OF_OPTION_MAP *OneOfOptionMap; + FORM_BROWSER_FORMSET *FormSet; + + FormSet = ThunkContext->FormSet; - Link = GetFirstNode (&ThunkContext->OneOfOptionMapListHead); + Link = GetFirstNode (&FormSet->OneOfOptionMapListHead); - while (!IsNull (&ThunkContext->OneOfOptionMapListHead, Link)) { + while (!IsNull (&FormSet->OneOfOptionMapListHead, Link)) { OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link); if (OneOfOptionMap->QuestionId == QuestionId) { ASSERT (OneOfOptionMap->ValueType == Type); @@ -743,7 +822,7 @@ GetOneOfOptionMapEntry ( } } - Link = GetNextNode (&ThunkContext->OneOfOptionMapListHead, Link); + Link = GetNextNode (&FormSet->OneOfOptionMapListHead, Link); } @@ -757,6 +836,18 @@ GetOneOfOptionMapEntry ( PackageGuid, Handle, and Package are used for each of the notification types. + If any Pakcage List in database is updated, mHiiPackageListUpdated + will be set. If mHiiPackageListUpdated is set, Framework ThunkCallback() + will force the UEFI Setup Browser to save the uncommitted data. This + is needed as Framework's Callback function may dynamically update + opcode in a Package List. UEFI Setup Browser will quit itself and reparse + the Package List's IFR and display it. UEFI Config Access's implementation + is required to save the modified (SetBrowserData or directly save the data + to NV storage). But Framework HII Modules is not aware of this rule. Therefore, + we will enforce the rule in ThunkCallback (). The side effect of force saving + of NV data is the NV flag in browser may not flag a update as data has already + been saved to NV storage. + @param PackageType Package type of the notification. @param PackageGuid If PackageType is @@ -793,8 +884,7 @@ FormUpdateNotify ( /** Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack to EFI_FORM_CALLBACK_PROTOCOL.Callback. Therefor, - the framework HII module willl do no porting (except some porting works needed for callback for EFI_ONE_OF_OPTION opcode) - and still work with a UEFI HII SetupBrowser. + the framework HII module willl do no porting and work with a UEFI HII SetupBrowser. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Action Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x. @@ -864,6 +954,9 @@ ThunkCallback ( // KeyValue = QuestionId; } else { + // + // Otherwise, use the original Key specified in One Of Option in the Framework VFR syntax. + // KeyValue = OneOfOptionMapEntry->FwKey; } @@ -874,14 +967,14 @@ ThunkCallback ( Status = mHiiDatabase->RegisterPackageNotify ( mHiiDatabase, - EFI_HII_PACKAGE_FORM, + EFI_HII_PACKAGE_FORMS, NULL, FormUpdateNotify, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, &NotifyHandle ); // - // + //Call the Framework Callback function. // Packet = NULL; Status = FormCallbackProtocol->Callback ( @@ -890,24 +983,17 @@ ThunkCallback ( Data, &Packet ); - SyncBrowserDataForNvMapOverride (ConfigAccess); + SyncBrowserDataForNvMapOverride (ConfigAccess, QuestionId); // // Callback require browser to perform action // if (EFI_ERROR (Status)) { if (Packet != NULL) { - // - // BUGBUG: need to restore the changing question to default value - // - do { IfrLibCreatePopUp (1, &Key, Packet->String); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - } - // // Error Code in Status is discarded. // @@ -939,7 +1025,7 @@ ThunkCallback ( NotifyHandle ); // - // UEFI SetupBrowser handles scenario differently with Framework SetupBrowser when call back function + // UEFI SetupBrowser behaves differently with Framework SetupBrowser when call back function // update any forms in HII database. UEFI SetupBrowser will re-parse the displaying form package and load // the values from variable storages. Framework SetupBrowser will only re-parse the displaying form packages. // To make sure customer's previous changes is saved and the changing question behaves as expected, we @@ -947,9 +1033,19 @@ ThunkCallback ( // the form and load all the variable storages. // if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) { + mHiiPackageListUpdated= FALSE; *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + } else { + if (ConfigAccess->ThunkContext->FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS || + ConfigAccess->ThunkContext->FormSet->SubClass == EFI_SINGLE_USE_SUBCLASS) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } } + + // + // Clean up. + // DestroyIfrDataArray (Data, NvMapAllocated); return Status;