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