mirror of https://github.com/acidanthera/audk.git
968 lines
34 KiB
C
968 lines
34 KiB
C
/**@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.
|
|
|
|
Copyright (c) 2008, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "HiiDatabase.h"
|
|
|
|
BOOLEAN mHiiPackageListUpdated;
|
|
|
|
CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = {
|
|
CONFIG_ACCESS_PRIVATE_SIGNATURE,
|
|
{
|
|
ThunkExtractConfig,
|
|
ThunkRouteConfig,
|
|
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.
|
|
|
|
@param Packages The Framework Package List
|
|
|
|
@retval EFI_HII_PACKAGE_HEADER* Return the Package Header of Form Package.
|
|
@retval NULL If no Form Package is found.
|
|
**/
|
|
EFI_HII_PACKAGE_HEADER *
|
|
GetIfrFormSet (
|
|
IN CONST EFI_HII_PACKAGES *Packages
|
|
)
|
|
{
|
|
TIANO_AUTOGEN_PACKAGES_HEADER **TianoAutogenPackageHdrArray;
|
|
EFI_HII_PACKAGE_HEADER *IfrPackage;
|
|
UINTN Index;
|
|
|
|
ASSERT (Packages != NULL);
|
|
|
|
IfrPackage = NULL;
|
|
|
|
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;
|
|
|
|
case EFI_HII_PACKAGE_STRINGS:
|
|
case EFI_HII_PACKAGE_SIMPLE_FONTS:
|
|
break;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
return (EFI_HII_PACKAGE_HEADER *) 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.
|
|
|
|
@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.
|
|
**/
|
|
EFI_STATUS
|
|
GetBufferStorage (
|
|
IN CONST EFI_HII_PACKAGE_HEADER *FormSetPackage,
|
|
OUT LIST_ENTRY *BufferStorageListHead
|
|
)
|
|
{
|
|
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);
|
|
|
|
BufferStorage->VarStoreId = VarStoreOpCode->VarStoreId;
|
|
|
|
BufferStorage->Size = VarStoreOpCode->Size;
|
|
BufferStorage->Signature = BUFFER_STORAGE_ENTRY_SIGNATURE;
|
|
|
|
InsertTailList (BufferStorageListHead, &BufferStorage->Link);
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
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.
|
|
|
|
@param Packages The framework package list.
|
|
@param ThunkContext The Thunk Layer Handle Mapping Database Entry.
|
|
|
|
@retval EFI_SUCCESS The Config Access Protocol is installed successfully.
|
|
@retval EFI_OUT_RESOURCE There is not enough memory.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InstallDefaultConfigAccessProtocol (
|
|
IN CONST EFI_HII_PACKAGES *Packages,
|
|
IN OUT HII_THUNK_CONTEXT *ThunkContext
|
|
)
|
|
{
|
|
EFI_HII_PACKAGE_HEADER *FormSetPackage;
|
|
EFI_STATUS Status;
|
|
CONFIG_ACCESS_PRIVATE *ConfigAccessInstance;
|
|
|
|
Status = HiiLibCreateHiiDriverHandle (&ThunkContext->UefiHiiDriverHandle);
|
|
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);
|
|
|
|
FreePool (Entry);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UninstallDefaultConfigAccessProtocol (
|
|
IN HII_THUNK_CONTEXT *ThunkContext
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
|
|
CONFIG_ACCESS_PRIVATE *ConfigAccessInstance;
|
|
|
|
HiiLibDestroyHiiDriverHandle (ThunkContext->UefiHiiDriverHandle);
|
|
|
|
Status = gBS->HandleProtocol (
|
|
ThunkContext->UefiHiiDriverHandle,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
(VOID **) &ConfigAccess
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = gBS->UninstallProtocolInterface (
|
|
ThunkContext->UefiHiiDriverHandle,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
ConfigAccess
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
ConfigAccessInstance = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (ConfigAccess);
|
|
|
|
DestroyBufferStorageList (&ConfigAccessInstance->BufferStorageListHead);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to EFI_FORM_CALLBACK_PROTOCOL.NvRead.
|
|
|
|
@param BufferStorage The key with all attributes needed to call EFI_FORM_CALLBACK_PROTOCOL.NvRead.
|
|
@param FwFormCallBack The EFI_FORM_CALLBACK_PROTOCOL registered by Framework HII module.
|
|
@param Data The data read.
|
|
@param DataSize The size of data.
|
|
|
|
@retval EFI_STATUS The status returned by the EFI_FORM_CALLBACK_PROTOCOL.NvWrite.
|
|
@retval EFI_INVALID_PARAMETER If the EFI_FORM_CALLBACK_PROTOCOL.NvRead return the size information of the data
|
|
does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.
|
|
**/
|
|
EFI_STATUS
|
|
CallFormCallBack (
|
|
IN BUFFER_STORAGE_ENTRY *BufferStorage,
|
|
IN EFI_FORM_CALLBACK_PROTOCOL *FwFormCallBack,
|
|
OUT VOID **Data,
|
|
OUT UINTN *DataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
*DataSize = 0;
|
|
*Data = NULL;
|
|
|
|
Status = FwFormCallBack->NvRead (
|
|
FwFormCallBack,
|
|
BufferStorage->Name,
|
|
&BufferStorage->Guid,
|
|
NULL,
|
|
DataSize,
|
|
*Data
|
|
);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
if (BufferStorage->Size != *DataSize) {
|
|
ASSERT (FALSE);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Data = AllocateZeroPool (*DataSize);
|
|
if (Data == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
FwFormCallBack->NvRead (
|
|
FwFormCallBack,
|
|
BufferStorage->Name,
|
|
&BufferStorage->Guid,
|
|
NULL,
|
|
DataSize,
|
|
*Data
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to UEFI Variable Get Service.
|
|
|
|
@param BufferStorage The key with all attributes needed to call a UEFI Variable Get Service.
|
|
@param Data The data read.
|
|
@param DataSize The size of data.
|
|
|
|
If the UEFI Variable Get Service return the size information of the data
|
|
does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.
|
|
then ASSERT.
|
|
|
|
@retval EFI_STATUS The status returned by the UEFI Variable Get Service.
|
|
@retval EFI_INVALID_PARAMETER If the UEFI Variable Get Service return the size information of the data
|
|
does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.
|
|
**/
|
|
|
|
EFI_STATUS
|
|
GetUefiVariable (
|
|
IN BUFFER_STORAGE_ENTRY *BufferStorage,
|
|
OUT VOID **Data,
|
|
OUT UINTN *DataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
*DataSize = 0;
|
|
*Data = NULL;
|
|
Status = gRT->GetVariable (
|
|
BufferStorage->Name,
|
|
&BufferStorage->Guid,
|
|
NULL,
|
|
DataSize,
|
|
*Data
|
|
);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
if (BufferStorage->Size != *DataSize) {
|
|
ASSERT (FALSE);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Data = AllocateZeroPool (*DataSize);
|
|
if (Data == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = gRT->GetVariable (
|
|
BufferStorage->Name,
|
|
&BufferStorage->Guid,
|
|
NULL,
|
|
DataSize,
|
|
*Data
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BUFFER_STORAGE_ENTRY *
|
|
GetBufferStorageEntry (
|
|
IN CONFIG_ACCESS_PRIVATE *ConfigAccess,
|
|
IN UINT16 VarStoreId
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
BUFFER_STORAGE_ENTRY *BufferStorage;
|
|
|
|
Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);
|
|
|
|
while (!IsNull (&ConfigAccess->BufferStorageListHead, Link)) {
|
|
BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link);
|
|
|
|
if (BufferStorage->VarStoreId == VarStoreId) {
|
|
return BufferStorage;
|
|
}
|
|
|
|
Link = GetNextNode (&ConfigAccess->BufferStorageListHead, Link);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig
|
|
so that data can be read from the data storage such as UEFI Variable or module's
|
|
customized storage exposed by EFI_FRAMEWORK_CALLBACK.
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL
|
|
@param Request A null-terminated Unicode string in <ConfigRequest> format. Note that this
|
|
includes the routing information as well as the configurable name / value pairs. It is
|
|
invalid for this string to be in <MultiConfigRequest> format.
|
|
|
|
@param Progress On return, points to a character in the Request string. Points to the string's null
|
|
terminator if request was successful. Points to the most recent '&' before the first
|
|
failing name / value pair (or the beginning of the string if the failure is in the first
|
|
name / value pair) if the request was not successful
|
|
@param Results A null-terminated Unicode string in <ConfigAltResp> format which has all
|
|
values filled in for the names in the Request string. String to be allocated by the called
|
|
function.
|
|
|
|
@retval EFI_INVALID_PARAMETER If there is no Buffer Storage for this Config Access instance.
|
|
@retval EFI_SUCCESS The setting is retrived successfully.
|
|
@retval !EFI_SUCCESS The error returned by UEFI Get Variable or Framework Form Callback Nvread.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ThunkExtractConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Request,
|
|
OUT EFI_STRING *Progress,
|
|
OUT EFI_STRING *Results
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CONFIG_ACCESS_PRIVATE *ConfigAccess;
|
|
BUFFER_STORAGE_ENTRY *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.
|
|
//
|
|
BufferStorage = GetBufferStorageEntry (ConfigAccess, (UINT16) RESERVED_VARSTORE_ID);
|
|
|
|
if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {
|
|
if (ConfigAccess->FormCallbackProtocol == NULL ||
|
|
ConfigAccess->FormCallbackProtocol->NvRead == NULL) {
|
|
Status = GetUefiVariable (
|
|
BufferStorage,
|
|
&Data,
|
|
&DataSize
|
|
);
|
|
} else {
|
|
Status = CallFormCallBack (
|
|
BufferStorage,
|
|
ConfigAccess->FormCallbackProtocol,
|
|
&Data,
|
|
&DataSize
|
|
);
|
|
}
|
|
} else {
|
|
DataSize = BufferStorage->Size;
|
|
Data = AllocateCopyPool (DataSize, ConfigAccess->ThunkContext->NvMapOverride);
|
|
|
|
if (Data != NULL) {
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = mHiiConfigRoutingProtocol->BlockToConfig (
|
|
mHiiConfigRoutingProtocol,
|
|
Request,
|
|
Data,
|
|
DataSize,
|
|
Results,
|
|
Progress
|
|
);
|
|
}
|
|
|
|
SafeFreePool (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.
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL
|
|
@param Configuration A null-terminated Unicode string in <ConfigResp> format.
|
|
@param Progress A pointer to a string filled in with the offset of the most recent '&' before the first
|
|
failing name / value pair (or the beginning of the string if the failure is in the first
|
|
name / value pair) or the terminating NULL if all was successful.
|
|
|
|
@retval EFI_INVALID_PARAMETER If there is no Buffer Storage for this Config Access instance.
|
|
@retval EFI_SUCCESS The setting is saved successfully.
|
|
@retval !EFI_SUCCESS The error returned by UEFI Set Variable or Framework Form Callback Nvwrite.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ThunkRouteConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Configuration,
|
|
OUT EFI_STRING *Progress
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CONFIG_ACCESS_PRIVATE *ConfigAccess;
|
|
BUFFER_STORAGE_ENTRY *BufferStorage;
|
|
UINT8 *Data;
|
|
UINTN DataSize;
|
|
UINTN DataSize2;
|
|
UINTN LastModifiedByteIndex;
|
|
BOOLEAN ResetRequired;
|
|
BOOLEAN DataAllocated;
|
|
|
|
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.
|
|
//
|
|
BufferStorage = GetBufferStorageEntry (ConfigAccess, (UINT16) RESERVED_VARSTORE_ID);
|
|
|
|
DataSize2 = BufferStorage->Size;
|
|
if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {
|
|
DataAllocated = TRUE;
|
|
if (ConfigAccess->FormCallbackProtocol == NULL ||
|
|
ConfigAccess->FormCallbackProtocol->NvRead == NULL) {
|
|
Status = GetUefiVariable (
|
|
BufferStorage,
|
|
&Data,
|
|
&DataSize
|
|
);
|
|
} else {
|
|
Status = CallFormCallBack (
|
|
BufferStorage,
|
|
ConfigAccess->FormCallbackProtocol,
|
|
&Data,
|
|
&DataSize
|
|
);
|
|
}
|
|
} else {
|
|
//
|
|
// ConfigToBlock will convert the Config String and update the NvMapOverride accordingly.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
Data = ConfigAccess->ThunkContext->NvMapOverride;
|
|
DataSize = DataSize2;
|
|
DataAllocated = FALSE;
|
|
}
|
|
if (EFI_ERROR (Status) || (DataSize2 != DataSize)) {
|
|
if (Data == NULL) {
|
|
Data = AllocateZeroPool (DataSize2);
|
|
}
|
|
}
|
|
|
|
Status = mHiiConfigRoutingProtocol->ConfigToBlock (
|
|
mHiiConfigRoutingProtocol,
|
|
Configuration,
|
|
Data,
|
|
&LastModifiedByteIndex,
|
|
Progress
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {
|
|
if (ConfigAccess->FormCallbackProtocol == NULL ||
|
|
ConfigAccess->FormCallbackProtocol->NvWrite == NULL) {
|
|
Status = gRT->SetVariable (
|
|
BufferStorage->Name,
|
|
&BufferStorage->Guid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
DataSize2,
|
|
Data
|
|
);
|
|
} else {
|
|
Status = ConfigAccess->FormCallbackProtocol->NvWrite (
|
|
ConfigAccess->FormCallbackProtocol,
|
|
BufferStorage->Name,
|
|
&BufferStorage->Guid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
DataSize2,
|
|
Data,
|
|
&ResetRequired
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
Done:
|
|
if (DataAllocated && (Data != NULL)) {
|
|
FreePool (Data);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
FRAMEWORK_EFI_IFR_DATA_ARRAY *
|
|
CreateIfrDataArray (
|
|
IN CONFIG_ACCESS_PRIVATE *ConfigAccess,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value,
|
|
OUT BOOLEAN *NvMapAllocated
|
|
)
|
|
{
|
|
FRAMEWORK_EFI_IFR_DATA_ARRAY *IfrDataArray;
|
|
FRAMEWORK_EFI_IFR_DATA_ENTRY *IfrDataEntry;
|
|
UINTN BrowserDataSize;
|
|
BUFFER_STORAGE_ENTRY *BufferStorageEntry;
|
|
LIST_ENTRY *Link;
|
|
EFI_STATUS Status;
|
|
|
|
Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);
|
|
if (IsNull (&ConfigAccess->BufferStorageListHead, Link)) {
|
|
return NULL;
|
|
}
|
|
|
|
IfrDataArray = AllocateZeroPool (0x100);
|
|
ASSERT (IfrDataArray != NULL);
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
break;
|
|
}
|
|
|
|
return IfrDataArray;
|
|
}
|
|
|
|
VOID
|
|
SyncBrowserDataForNvMapOverride (
|
|
IN CONFIG_ACCESS_PRIVATE *ConfigAccess
|
|
)
|
|
{
|
|
BUFFER_STORAGE_ENTRY *BufferStorageEntry;
|
|
LIST_ENTRY *Link;
|
|
EFI_STATUS Status;
|
|
UINTN BrowserDataSize;
|
|
|
|
if (ConfigAccess->ThunkContext->NvMapOverride != NULL) {
|
|
|
|
Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);
|
|
ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link));
|
|
|
|
BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);
|
|
BrowserDataSize = BufferStorageEntry->Size;
|
|
|
|
Status = SetBrowserData (NULL, NULL, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
DestroyIfrDataArray (
|
|
IN FRAMEWORK_EFI_IFR_DATA_ARRAY *Array,
|
|
IN BOOLEAN NvMapAllocated
|
|
)
|
|
{
|
|
if (Array != NULL) {
|
|
if (NvMapAllocated) {
|
|
FreePool (Array->NvRamMap);
|
|
}
|
|
|
|
FreePool (Array);
|
|
}
|
|
}
|
|
|
|
|
|
ONE_OF_OPTION_MAP_ENTRY *
|
|
GetOneOfOptionMapEntry (
|
|
IN HII_THUNK_CONTEXT *ThunkContext,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *Link2;
|
|
ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;
|
|
ONE_OF_OPTION_MAP *OneOfOptionMap;
|
|
|
|
Link = GetFirstNode (&ThunkContext->OneOfOptionMapListHead);
|
|
|
|
while (!IsNull (&ThunkContext->OneOfOptionMapListHead, Link)) {
|
|
OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);
|
|
if (OneOfOptionMap->QuestionId == QuestionId) {
|
|
ASSERT (OneOfOptionMap->ValueType == Type);
|
|
|
|
Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);
|
|
|
|
while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {
|
|
OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);
|
|
|
|
if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {
|
|
return OneOfOptionMapEntry;
|
|
}
|
|
|
|
Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);
|
|
}
|
|
}
|
|
|
|
Link = GetNextNode (&ThunkContext->OneOfOptionMapListHead, Link);
|
|
}
|
|
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Functions which are registered to receive notification of
|
|
database events have this prototype. The actual event is encoded
|
|
in NotifyType. The following table describes how PackageType,
|
|
PackageGuid, Handle, and Package are used for each of the
|
|
notification types.
|
|
|
|
@param PackageType Package type of the notification.
|
|
|
|
@param PackageGuid If PackageType is
|
|
EFI_HII_PACKAGE_TYPE_GUID, then this is
|
|
the pointer to the GUID from the Guid
|
|
field of EFI_HII_PACKAGE_GUID_HEADER.
|
|
Otherwise, it must be NULL.
|
|
|
|
@param Package Points to the package referred to by the
|
|
notification Handle The handle of the package
|
|
list which contains the specified package.
|
|
|
|
@param Handle The HII handle.
|
|
|
|
@param NotifyType The type of change concerning the
|
|
database. See
|
|
EFI_HII_DATABASE_NOTIFY_TYPE.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FormUpdateNotify (
|
|
IN UINT8 PackageType,
|
|
IN CONST EFI_GUID *PackageGuid,
|
|
IN CONST EFI_HII_PACKAGE_HEADER *Package,
|
|
IN EFI_HII_HANDLE Handle,
|
|
IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType
|
|
)
|
|
{
|
|
mHiiPackageListUpdated = TRUE;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@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.
|
|
@param QuestionId A unique value which is sent to the original exporting driver so that it can identify the
|
|
type of data to expect. The format of the data tends to vary based on the opcode that
|
|
generated the callback.
|
|
@param Type The type of value for the question. See EFI_IFR_TYPE_x in
|
|
EFI_IFR_ONE_OF_OPTION.
|
|
@param Value A pointer to the data being sent to the original exporting driver. The type is specified
|
|
by Type. Type EFI_IFR_TYPE_VALUE is defined in
|
|
EFI_IFR_ONE_OF_OPTION.
|
|
@param ActionRequest On return, points to the action requested by the callback function. Type
|
|
EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form
|
|
Browser Protocol.
|
|
|
|
@retval EFI_UNSUPPORTED If the Framework HII module does not register Callback although it specify the opcode under
|
|
focuse to be INTERRACTIVE.
|
|
@retval EFI_SUCCESS The callback complete successfully.
|
|
@retval !EFI_SUCCESS The error code returned by EFI_FORM_CALLBACK_PROTOCOL.Callback.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ThunkCallback (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN EFI_BROWSER_ACTION Action,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value,
|
|
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CONFIG_ACCESS_PRIVATE *ConfigAccess;
|
|
EFI_FORM_CALLBACK_PROTOCOL *FormCallbackProtocol;
|
|
EFI_HII_CALLBACK_PACKET *Packet;
|
|
FRAMEWORK_EFI_IFR_DATA_ARRAY *Data;
|
|
FRAMEWORK_EFI_IFR_DATA_ENTRY *DataEntry;
|
|
UINT16 KeyValue;
|
|
ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;
|
|
EFI_HANDLE NotifyHandle;
|
|
EFI_INPUT_KEY Key;
|
|
BOOLEAN NvMapAllocated;
|
|
|
|
ASSERT (This != NULL);
|
|
ASSERT (Value != NULL);
|
|
ASSERT (ActionRequest != NULL);
|
|
|
|
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
|
|
|
|
ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);
|
|
|
|
FormCallbackProtocol = ConfigAccess->FormCallbackProtocol;
|
|
if (FormCallbackProtocol == NULL) {
|
|
ASSERT (FALSE);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Check if the QuestionId match a OneOfOption.
|
|
//
|
|
OneOfOptionMapEntry = GetOneOfOptionMapEntry (ConfigAccess->ThunkContext, QuestionId, Type, Value);
|
|
|
|
if (OneOfOptionMapEntry == NULL) {
|
|
//
|
|
// This is not a One-Of-Option opcode. QuestionId is the KeyValue
|
|
//
|
|
KeyValue = QuestionId;
|
|
} else {
|
|
KeyValue = OneOfOptionMapEntry->FwKey;
|
|
}
|
|
|
|
//
|
|
// Build the FRAMEWORK_EFI_IFR_DATA_ARRAY
|
|
//
|
|
Data = CreateIfrDataArray (ConfigAccess, QuestionId, Type, Value, &NvMapAllocated);
|
|
|
|
Status = mHiiDatabase->RegisterPackageNotify (
|
|
mHiiDatabase,
|
|
EFI_HII_PACKAGE_FORM,
|
|
NULL,
|
|
FormUpdateNotify,
|
|
EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
|
|
&NotifyHandle
|
|
);
|
|
//
|
|
//
|
|
//
|
|
Packet = NULL;
|
|
Status = FormCallbackProtocol->Callback (
|
|
FormCallbackProtocol,
|
|
KeyValue,
|
|
Data,
|
|
&Packet
|
|
);
|
|
SyncBrowserDataForNvMapOverride (ConfigAccess);
|
|
|
|
//
|
|
// Callback require browser to perform action
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
if (Packet != NULL) {
|
|
do {
|
|
IfrLibCreatePopUp (1, &Key, Packet->String);
|
|
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
|
|
}
|
|
//
|
|
// Error Code in Status is discarded.
|
|
//
|
|
} else {
|
|
if (Packet != NULL) {
|
|
if (Packet->DataArray.EntryCount == 1 && Packet->DataArray.NvRamMap == NULL) {
|
|
DataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY));
|
|
if ((DataEntry->Flags & EXIT_REQUIRED) == EXIT_REQUIRED) {
|
|
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
|
|
}
|
|
|
|
if ((DataEntry->Flags & SAVE_REQUIRED) == SAVE_REQUIRED) {
|
|
Status = ConfigAccess->ConfigAccessProtocol.RouteConfig (
|
|
&ConfigAccess->ConfigAccessProtocol,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
FreePool (Packet);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Unregister notify for Form package update
|
|
//
|
|
Status = mHiiDatabase->UnregisterPackageNotify (
|
|
mHiiDatabase,
|
|
NotifyHandle
|
|
);
|
|
//
|
|
// 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
|
|
// issue a EFI_BROWSER_ACTION_REQUEST_SUBMIT to ask UEFI SetupBrowser to save the changes proceed to re-parse
|
|
// the form and load all the variable storages.
|
|
//
|
|
if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) {
|
|
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
|
|
}
|
|
|
|
|
|
DestroyIfrDataArray (Data, NvMapAllocated);
|
|
|
|
return Status;
|
|
}
|
|
|