Skip to content

Commit

Permalink
UefiPayloadPkg: CFR fixes and improvements (#28)
Browse files Browse the repository at this point in the history
* UefiPayloadPkg/CfrSetupMenuDxe: Implement option dependencies

* UefiPayloadPkg: Sync CFR option flags with coreboot

Change the GRAYOUT CFR option flag to INACTIVE and add the RUNTIME flag
to match coreboot.

* UefiPayloadPkg/CfrSetupMenuDxe: Check for CFR RUNTIME option flag

Use the CFR RUNTIME option flag to set the EFI_VARIABLE_RUNTIME_ACCESS
variable attribute.

Signed-off-by: Filip Brozovic <[email protected]>
  • Loading branch information
fbrozovic authored Jan 16, 2025
1 parent 3ff67d4 commit 2d1b882
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 8 deletions.
207 changes: 201 additions & 6 deletions UefiPayloadPkg/CfrSetupMenuDxe/SetupMenuCfr.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,25 @@ CfrConvertVarBinaryToStrings (
}
}

/**
CFR_VARBINARY records are used to store a list of dependency values.
Get a pointer to an array of enum values and its length.
**/
STATIC
VOID
EFIAPI
CfrConvertVarBinaryToUint32Array (
IN CFR_VARBINARY *CfrList,
IN OUT UINT32 **Array,
OUT UINT32 *ArrayLength
)
{
ASSERT ((CfrList != NULL) && (Array != NULL) && (ArrayLength != NULL));

*Array = (UINT32 *)CfrList->data;
*ArrayLength = CfrList->data_length / sizeof (UINT32);
}

/**
Produce unconditional HII `*_IF` for CFR flags.
Expand Down Expand Up @@ -107,6 +126,101 @@ CfrProduceHiiForFlags (
ASSERT (TempHiiBuffer != NULL);
}

/**
Produce conditional HII `SUPPRESS_IF` based on a dependency:
Caller to close each `SUPPRESS_IF` with `HiiCreateEndOpCode()`.
**/
STATIC
VOID
EFIAPI
CfrProduceHiiForDependency (
IN VOID *StartOpCodeHandle,
IN UINTN DependencyId,
IN UINT32 *DepValues,
IN UINT32 NumDepValues
)
{
EFI_IFR_OP_HEADER OpHeader;
UINT8 *TempHiiBuffer;
UINTN EqIdValListSize;
EFI_IFR_EQ_ID_VAL_LIST *EqIdValList;
EFI_IFR_EQ_ID_VAL EqIdVal;
UINTN Index;

OpHeader.OpCode = EFI_IFR_SUPPRESS_IF_OP;
OpHeader.Length = sizeof (EFI_IFR_OP_HEADER);
OpHeader.Scope = 1;

TempHiiBuffer = HiiCreateRawOpCodes (
StartOpCodeHandle,
(UINT8 *)&OpHeader,
sizeof (EFI_IFR_OP_HEADER)
);
ASSERT (TempHiiBuffer != NULL);

if (NumDepValues != 0) {
EqIdValListSize = sizeof (EFI_IFR_EQ_ID_VAL_LIST) + ((NumDepValues - 1) * sizeof (UINT16));
EqIdValList = AllocatePool (EqIdValListSize);
ASSERT (EqIdValList != NULL);

EqIdValList->Header.OpCode = EFI_IFR_EQ_ID_VAL_LIST_OP;
EqIdValList->Header.Length = EqIdValListSize;
EqIdValList->Header.Scope = 1;

EqIdValList->QuestionId = DependencyId;
EqIdValList->ListLength = NumDepValues;
for (Index = 0; Index < NumDepValues; Index++) {
EqIdValList->ValueList[Index] = (UINT16)*DepValues++;
}

TempHiiBuffer = HiiCreateRawOpCodes (
StartOpCodeHandle,
(UINT8 *)EqIdValList,
EqIdValListSize
);
ASSERT (TempHiiBuffer != NULL);

FreePool (EqIdValList);

OpHeader.OpCode = EFI_IFR_NOT_OP;
OpHeader.Length = sizeof (EFI_IFR_OP_HEADER);
OpHeader.Scope = 0;

TempHiiBuffer = HiiCreateRawOpCodes (
StartOpCodeHandle,
(UINT8 *)&OpHeader,
sizeof (EFI_IFR_OP_HEADER)
);
ASSERT (TempHiiBuffer != NULL);
} else {
EqIdVal.Header.OpCode = EFI_IFR_EQ_ID_VAL_OP;
EqIdVal.Header.Length = sizeof (EFI_IFR_EQ_ID_VAL);
EqIdVal.Header.Scope = 1;
EqIdVal.QuestionId = DependencyId;
EqIdVal.Value = 0;

TempHiiBuffer = HiiCreateRawOpCodes (
StartOpCodeHandle,
(UINT8 *)&EqIdVal,
sizeof (EFI_IFR_EQ_ID_VAL)
);
ASSERT (TempHiiBuffer != NULL);
}

OpHeader.OpCode = EFI_IFR_END_OP;
OpHeader.Length = sizeof (EFI_IFR_OP_HEADER);
OpHeader.Scope = 0;

TempHiiBuffer = HiiCreateRawOpCodes (
StartOpCodeHandle,
(UINT8 *)&OpHeader,
sizeof (EFI_IFR_OP_HEADER)
);
ASSERT (TempHiiBuffer != NULL);
}

/**
Produce variable and VARSTORE for CFR option name.
Expand Down Expand Up @@ -144,6 +258,9 @@ CfrProduceStorageForOption (
if (!(OptionFlags & CFR_OPTFLAG_VOLATILE)) {
VariableAttributes |= EFI_VARIABLE_NON_VOLATILE;
}
if (OptionFlags & CFR_OPTFLAG_RUNTIME) {
VariableAttributes |= EFI_VARIABLE_RUNTIME_ACCESS;
}

DataSize = 0;
Status = gRT->GetVariable (
Expand Down Expand Up @@ -240,6 +357,9 @@ CfrProcessFormOption (
)
{
CFR_VARBINARY *CfrFormName;
UINT32 *DepValues;
UINT32 NumDepValues;
CFR_VARBINARY *CfrDepValues;
CHAR16 *HiiFormNameString;
EFI_STRING_ID HiiFormNameStringId;
UINT8 *TempHiiBuffer;
Expand All @@ -251,6 +371,15 @@ CfrProcessFormOption (
CfrFormName = CfrExtractVarBinary ((UINT8 *)Option, ProcessedLength, CB_TAG_CFR_VARCHAR_UI_NAME);
ASSERT (CfrFormName != NULL);

// Dependency values are optional
DepValues = NULL;
NumDepValues = 0;
CfrDepValues = CfrExtractVarBinary ((UINT8 *)Option, ProcessedLength, CB_TAG_CFR_DEP_VALUES);
if (CfrDepValues != NULL) {
ASSERT (CfrDepValues->tag == CB_TAG_CFR_DEP_VALUES);
CfrConvertVarBinaryToUint32Array (CfrDepValues, &DepValues, &NumDepValues);
}

DEBUG ((
DEBUG_INFO,
"CFR: Processing form \"%a\", size 0x%x\n",
Expand All @@ -261,10 +390,19 @@ CfrProcessFormOption (
CfrConvertVarBinaryToStrings (CfrFormName, &HiiFormNameString, &HiiFormNameStringId);
FreePool (HiiFormNameString);

if (Option->dependency_id) {
CfrProduceHiiForDependency (
StartOpCodeHandle,
CFR_COMPONENT_START + Option->dependency_id,
DepValues,
NumDepValues
);
}

if (Option->flags & CFR_OPTFLAG_SUPPRESS) {
CfrProduceHiiForFlags (StartOpCodeHandle, EFI_IFR_SUPPRESS_IF_OP);
}
if (Option->flags & CFR_OPTFLAG_GRAYOUT) {
if (Option->flags & CFR_OPTFLAG_INACTIVE) {
CfrProduceHiiForFlags (StartOpCodeHandle, EFI_IFR_GRAY_OUT_IF_OP);
}

Expand All @@ -277,14 +415,19 @@ CfrProcessFormOption (
);
ASSERT (TempHiiBuffer != NULL);

if (Option->flags & CFR_OPTFLAG_GRAYOUT) {
if (Option->flags & CFR_OPTFLAG_INACTIVE) {
TempHiiBuffer = HiiCreateEndOpCode (StartOpCodeHandle);
ASSERT (TempHiiBuffer != NULL);
}
if (Option->flags & CFR_OPTFLAG_SUPPRESS) {
TempHiiBuffer = HiiCreateEndOpCode (StartOpCodeHandle);
ASSERT (TempHiiBuffer != NULL);
}

if (Option->dependency_id) {
TempHiiBuffer = HiiCreateEndOpCode (StartOpCodeHandle);
ASSERT (TempHiiBuffer != NULL);
}
}

/**
Expand All @@ -304,6 +447,9 @@ CfrProcessNumericOption (
CFR_VARBINARY *CfrOptionName;
CFR_VARBINARY *CfrDisplayName;
CFR_VARBINARY *CfrHelpText;
UINT32 *DepValues;
UINT32 NumDepValues;
CFR_VARBINARY *CfrDepValues;
UINTN QuestionIdVarStoreId;
UINT8 QuestionFlags;
VOID *DefaultOpCodeHandle;
Expand Down Expand Up @@ -334,6 +480,15 @@ CfrProcessNumericOption (
ASSERT (CfrHelpText->tag == CB_TAG_CFR_VARCHAR_UI_HELPTEXT);
}

// Dependency values are optional
DepValues = NULL;
NumDepValues = 0;
CfrDepValues = CfrExtractVarBinary ((UINT8 *)Option, &OptionProcessedLength, CB_TAG_CFR_DEP_VALUES);
if (CfrDepValues != NULL) {
ASSERT (CfrDepValues->tag == CB_TAG_CFR_DEP_VALUES);
CfrConvertVarBinaryToUint32Array (CfrDepValues, &DepValues, &NumDepValues);
}

DEBUG ((
DEBUG_INFO,
"CFR: Processing option \"%a\", size 0x%x\n",
Expand All @@ -359,10 +514,19 @@ CfrProcessNumericOption (
QuestionFlags |= EFI_IFR_FLAG_READ_ONLY;
}

if (Option->dependency_id) {
CfrProduceHiiForDependency (
StartOpCodeHandle,
CFR_COMPONENT_START + Option->dependency_id,
DepValues,
NumDepValues
);
}

if (Option->flags & CFR_OPTFLAG_SUPPRESS) {
CfrProduceHiiForFlags (StartOpCodeHandle, EFI_IFR_SUPPRESS_IF_OP);
}
if (Option->flags & CFR_OPTFLAG_GRAYOUT) {
if (Option->flags & CFR_OPTFLAG_INACTIVE) {
CfrProduceHiiForFlags (StartOpCodeHandle, EFI_IFR_GRAY_OUT_IF_OP);
}

Expand Down Expand Up @@ -461,7 +625,7 @@ CfrProcessNumericOption (
ASSERT (TempHiiBuffer != NULL);
}

if (Option->flags & CFR_OPTFLAG_GRAYOUT) {
if (Option->flags & CFR_OPTFLAG_INACTIVE) {
TempHiiBuffer = HiiCreateEndOpCode (StartOpCodeHandle);
ASSERT (TempHiiBuffer != NULL);
}
Expand All @@ -470,6 +634,11 @@ CfrProcessNumericOption (
ASSERT (TempHiiBuffer != NULL);
}

if (Option->dependency_id) {
TempHiiBuffer = HiiCreateEndOpCode (StartOpCodeHandle);
ASSERT (TempHiiBuffer != NULL);
}

if (OptionOpCodeHandle != NULL) {
HiiFreeOpCodeHandle (OptionOpCodeHandle);
}
Expand Down Expand Up @@ -497,6 +666,9 @@ CfrProcessCharacterOption (
CFR_VARBINARY *CfrDisplayName;
CFR_VARBINARY *CfrHelpText;
CFR_VARBINARY *CfrDefaultValue;
UINT32 *DepValues;
UINT32 NumDepValues;
CFR_VARBINARY *CfrDepValues;
UINTN QuestionIdVarStoreId;
CHAR16 *HiiDefaultValue;
EFI_STRING_ID HiiDefaultValueId;
Expand Down Expand Up @@ -540,6 +712,15 @@ CfrProcessCharacterOption (
ASSERT (CfrHelpText->tag == CB_TAG_CFR_VARCHAR_UI_HELPTEXT);
}

// Dependency values are optional
DepValues = NULL;
NumDepValues = 0;
CfrDepValues = CfrExtractVarBinary ((UINT8 *)Option, &OptionProcessedLength, CB_TAG_CFR_DEP_VALUES);
if (CfrDepValues != NULL) {
ASSERT (CfrDepValues->tag == CB_TAG_CFR_DEP_VALUES);
CfrConvertVarBinaryToUint32Array (CfrDepValues, &DepValues, &NumDepValues);
}

DEBUG ((
DEBUG_INFO,
"CFR: Processing option \"%a\", size 0x%x\n",
Expand Down Expand Up @@ -576,10 +757,19 @@ CfrProcessCharacterOption (
}
}

if (Option->dependency_id) {
CfrProduceHiiForDependency (
StartOpCodeHandle,
CFR_COMPONENT_START + Option->dependency_id,
DepValues,
NumDepValues
);
}

if (Option->flags & CFR_OPTFLAG_SUPPRESS) {
CfrProduceHiiForFlags (StartOpCodeHandle, EFI_IFR_SUPPRESS_IF_OP);
}
if (Option->flags & CFR_OPTFLAG_GRAYOUT) {
if (Option->flags & CFR_OPTFLAG_INACTIVE) {
CfrProduceHiiForFlags (StartOpCodeHandle, EFI_IFR_GRAY_OUT_IF_OP);
}

Expand Down Expand Up @@ -640,7 +830,7 @@ CfrProcessCharacterOption (
ASSERT (TempHiiBuffer != NULL);
}

if (Option->flags & CFR_OPTFLAG_GRAYOUT) {
if (Option->flags & CFR_OPTFLAG_INACTIVE) {
TempHiiBuffer = HiiCreateEndOpCode (StartOpCodeHandle);
ASSERT (TempHiiBuffer != NULL);
}
Expand All @@ -649,6 +839,11 @@ CfrProcessCharacterOption (
ASSERT (TempHiiBuffer != NULL);
}

if (Option->dependency_id) {
TempHiiBuffer = HiiCreateEndOpCode (StartOpCodeHandle);
ASSERT (TempHiiBuffer != NULL);
}

ASSERT (OptionProcessedLength == Option->size);
*ProcessedLength += Option->size;
}
Expand Down
11 changes: 9 additions & 2 deletions UefiPayloadPkg/Include/Guid/CfrSetupMenuGuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,23 @@ extern EFI_GUID gEfiCfrSetupMenuFormGuid;
*/
enum cfr_option_flags {
CFR_OPTFLAG_READONLY = 1 << 0,
CFR_OPTFLAG_GRAYOUT = 1 << 1,
CFR_OPTFLAG_INACTIVE = 1 << 1,
CFR_OPTFLAG_SUPPRESS = 1 << 2,
CFR_OPTFLAG_VOLATILE = 1 << 3,
CFR_OPTFLAG_RUNTIME = 1 << 4,
};

#define CB_TAG_CFR_VARCHAR_OPT_NAME 0x0007
#define CB_TAG_CFR_VARCHAR_UI_NAME 0x0008
#define CB_TAG_CFR_VARCHAR_UI_HELPTEXT 0x0009
#define CB_TAG_CFR_VARCHAR_DEF_VALUE 0x000a
#define CB_TAG_CFR_DEP_VALUES 0x000c
#pragma pack (1)
typedef struct {
UINT32 tag; /*
* CFR_TAG_VARCHAR_OPT_NAME, CFR_TAG_VARCHAR_UI_NAME,
* CFR_TAG_VARCHAR_UI_HELPTEXT or CFR_TAG_VARCHAR_DEF_VALUE
* CFR_TAG_VARCHAR_UI_HELPTEXT, CFR_TAG_VARCHAR_DEF_VALUE
* or CFR_TAG_DEP_VALUES
*/
UINT32 size; /* Length of the entire structure */
UINT32 data_length; /* Length of data, including NULL terminator for strings */
Expand Down Expand Up @@ -81,6 +84,7 @@ typedef struct {
* CFR_VARCHAR_OPT_NAME opt_name
* CFR_VARCHAR_UI_NAME ui_name
* CFR_VARCHAR_UI_HELPTEXT ui_helptext (Optional)
* CFR_DEP_VALUES dependency_values (Optional)
* CFR_ENUM_VALUE enum_values[]
*/
} CFR_OPTION_NUMERIC;
Expand All @@ -96,6 +100,7 @@ typedef struct {
* CFR_OPT_NAME opt_name
* CFR_UI_NAME ui_name
* CFR_UI_HELPTEXT ui_helptext (Optional)
* CFR_DEP_VALUES dependency_values (Optional)
* CFR_VARCHAR default_value
*/
} CFR_OPTION_VARCHAR;
Expand All @@ -115,6 +120,7 @@ typedef struct {
/*
* CFR_UI_NAME ui_name
* CFR_UI_HELPTEXT ui_helptext (Optional)
* CFR_DEP_VALUES dependency_values (Optional)
*/
} CFR_OPTION_COMMENT;

Expand All @@ -128,6 +134,7 @@ typedef struct {
UINT32 flags; /* enum cfr_option_flags */
/*
* CFR_UI_NAME ui_name
* CFR_DEP_VALUES dependency_values (Optional)
* <T in CFR_OPTION> options[]
*/
} CFR_OPTION_FORM;
Expand Down

0 comments on commit 2d1b882

Please sign in to comment.