drivers/option: Add forms in cbtables
Introduce a mechanism so that coreboot can provide a list of options to post-coreboot code. The options are grouped together into forms and have a meaning name and optional help text. This can be used to let payloads know which options should be displayed in a setup menu, for instance. Although this system was written to be used with edk2, it has been designed with flexibility in mind so that other payloads can also make use of this mechanism. The system currently lacks a way to describe where to find option values. This information is stored in a set of data structures specifically created for this purpose. This format is known as CFR, which means "coreboot forms representation" or "cursed forms representation". Although the "forms representation" is borrowed from UEFI, CFR can be used in non-UEFI scenarios as well. The data structures are implemented as an extension of cbtables records to support nesting. It should not break backwards compatibility because the CFR root record (LB_TAG_CFR_ROOT) size includes all of its children records. The concept of record nesting is borrowed from the records for CMOS options. It is not possible to reuse the CMOS records because they are too closely coupled with CMOS options; using these structures would needlessly restrict more capable backends to what can be done with CMOS options, which is undesired. Because CFR supports variable-length components, directly transforming options into CFR structures is not a trivial process. Furthermore, CFR structures need to be written in one go. Because of this, abstractions exist to generate CFR structures from a set of "setup menu" structures that are coreboot-specific and could be integrated with the devicetree at some point. Note that `struct sm_object` is a tagged union. This is used to have lists of options in an array, as building linked lists of options at runtime is extremely impractical because options would have to be added at the end of the linked list to maintain option order. To avoid mistakes defining `struct sm_object` values, helper macros exist for supported option types. The macros also provide some type checking as they initialise specific union members. It should be possible to extend CFR support for more sophisticated options like fan curve points. Feedback about this is highly appreciated. Change-Id: I304de7d26d79245a2e31a6d01f6c5643b31cb772 Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/74121 Reviewed-by: Christian Walter <christian.walter@9elements.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
4d4776f320
commit
91fe658714
12 changed files with 1100 additions and 0 deletions
196
src/commonlib/include/commonlib/cfr.h
Normal file
196
src/commonlib/include/commonlib/cfr.h
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef COMMONLIB_OPTION_CFR_H
|
||||
#define COMMONLIB_OPTION_CFR_H
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/*
|
||||
* PUBLIC API
|
||||
*
|
||||
* The CFR table information is for conveying available boot
|
||||
* option of the firmware to the loaded OS image or payload.
|
||||
* Primarily this is expected to be information that is user
|
||||
* visible.
|
||||
*
|
||||
* The boot options are grouped into forms, where each form hold
|
||||
* one ore more options.
|
||||
* Boot options that are not used in the current boot flow, but
|
||||
* are reachable under certain conditions should be marked as hidden.
|
||||
*
|
||||
* A boot option can be one of the following types:
|
||||
* - boolean
|
||||
* - number
|
||||
* - enum
|
||||
* - string
|
||||
*
|
||||
* Each boot option has an UI name and UI help text that is free to
|
||||
* choose. All strings are in ASCII.
|
||||
*
|
||||
* All of the information should be Position Independent Data.
|
||||
* That is it should be safe to relocated any of the information
|
||||
* without it's meaning/correctness changing. For table that
|
||||
* can reasonably be used on multiple architectures the data
|
||||
* size should be fixed. This should ease the transition between
|
||||
* 32 bit and 64 bit architectures etc.
|
||||
*
|
||||
* CFR records form a tree structure. The size of a record includes
|
||||
* the size of its own fields plus the size of all children records.
|
||||
* CFR tags can appear multiple times except for `LB_TAG_CFR` which
|
||||
* is used for the root record.
|
||||
*
|
||||
* The following structures have comments that describe the supported
|
||||
* children records. These comments cannot be replaced with code! The
|
||||
* structures are variable-length, so the offsets won't be valid most
|
||||
* of the time. Besides, the implementation uses `sizeof()` to obtain
|
||||
* the size of the "record header" (the fixed-length members); adding
|
||||
* the children structures as struct members will increase the length
|
||||
* returned by `sizeof()`, which complicates things for zero reason.
|
||||
*
|
||||
*/
|
||||
|
||||
enum cfr_tags {
|
||||
CFR_TAG_OPTION_FORM = 1,
|
||||
CFR_TAG_ENUM_VALUE = 2,
|
||||
CFR_TAG_OPTION_ENUM = 3,
|
||||
CFR_TAG_OPTION_NUMBER = 4,
|
||||
CFR_TAG_OPTION_BOOL = 5,
|
||||
CFR_TAG_OPTION_VARCHAR = 6,
|
||||
CFR_TAG_VARCHAR_OPT_NAME = 7,
|
||||
CFR_TAG_VARCHAR_UI_NAME = 8,
|
||||
CFR_TAG_VARCHAR_UI_HELPTEXT = 9,
|
||||
CFR_TAG_VARCHAR_DEF_VALUE = 10,
|
||||
CFR_TAG_OPTION_COMMENT = 11,
|
||||
};
|
||||
|
||||
/*
|
||||
* The optional flags describe the visibilty of the option and the
|
||||
* effect on the non-volatile variable.
|
||||
* CFR_OPTFLAG_READONLY:
|
||||
* Prevents writes to the variable.
|
||||
* CFR_OPTFLAG_GRAYOUT:
|
||||
* Implies READONLY. The option is visible, but cannot be modified
|
||||
* because one of the dependencies are not given. However there's a
|
||||
* possibility to enable the option by changing runtime configuration.
|
||||
*
|
||||
* For example: Setting SATA mode, but SATA is globally disabled.
|
||||
* CFR_OPTFLAG_SUPPRESS:
|
||||
* Runtime code sets this flag to indicate that the option has no effect
|
||||
* and is never reachable, not even by changing runtime configuration.
|
||||
* This option is never shown in the UI.
|
||||
* CFR_OPTFLAG_VOLATILE:
|
||||
* Implies READONLY.
|
||||
* The option is not backed by a non-volatile variable. This is useful
|
||||
* to display the current state of a specific component, a dependency or
|
||||
* a serial number. This information could be passed in a new coreboot
|
||||
* table, but it not useful other than to be shown at this spot in the
|
||||
* UI.
|
||||
* CFR_OPTFLAG_RUNTIME:
|
||||
* The option is allowed to be changed by a post payload entity. On UEFI
|
||||
* this sets the EFI_VARIABLE_RUNTIME_ACCESS attribute.
|
||||
* It is out of scope of this specification how non runtime variables
|
||||
* are protected after the payload has hand over control.
|
||||
*/
|
||||
enum cfr_option_flags {
|
||||
CFR_OPTFLAG_READONLY = 1 << 0,
|
||||
CFR_OPTFLAG_GRAYOUT = 1 << 1,
|
||||
CFR_OPTFLAG_SUPPRESS = 1 << 2,
|
||||
CFR_OPTFLAG_VOLATILE = 1 << 3,
|
||||
CFR_OPTFLAG_RUNTIME = 1 << 4,
|
||||
};
|
||||
|
||||
struct __packed lb_cfr_varbinary {
|
||||
uint32_t tag; /*
|
||||
* CFR_TAG_VARCHAR_OPT_NAME, CFR_TAG_VARCHAR_UI_NAME,
|
||||
* CFR_TAG_VARCHAR_UI_HELPTEXT or CFR_TAG_VARCHAR_DEF_VALUE
|
||||
*/
|
||||
uint32_t size; /* Length of the entire structure */
|
||||
uint32_t data_length; /* Length of data, including NULL terminator for strings */
|
||||
};
|
||||
|
||||
struct __packed lb_cfr_enum_value {
|
||||
uint32_t tag; /* CFR_TAG_ENUM_VALUE */
|
||||
uint32_t size;
|
||||
uint32_t value;
|
||||
/*
|
||||
* struct lb_cfr_varbinary ui_name
|
||||
*/
|
||||
};
|
||||
|
||||
/* Supports multiple option types: ENUM, NUMBER, BOOL */
|
||||
struct __packed lb_cfr_numeric_option {
|
||||
uint32_t tag; /*
|
||||
* CFR_TAG_OPTION_ENUM, CFR_TAG_OPTION_NUMBER or
|
||||
* CFR_TAG_OPTION_BOOL
|
||||
*/
|
||||
uint32_t size;
|
||||
uint64_t object_id; /* Uniqueue ID */
|
||||
uint64_t dependency_id; /* Grayout if value of lb_cfr_numeric_option with given ID is 0.
|
||||
* Ignore if field is 0.
|
||||
*/
|
||||
uint32_t flags; /* enum cfr_option_flags */
|
||||
uint32_t default_value;
|
||||
/*
|
||||
* struct lb_cfr_varbinary opt_name
|
||||
* struct lb_cfr_varbinary ui_name
|
||||
* struct lb_cfr_varbinary ui_helptext (Optional)
|
||||
* struct lb_cfr_enum_value enum_values[]
|
||||
*/
|
||||
};
|
||||
|
||||
struct __packed lb_cfr_varchar_option {
|
||||
uint32_t tag; /* CFR_TAG_OPTION_VARCHAR */
|
||||
uint32_t size;
|
||||
uint64_t object_id; /* Uniqueue ID */
|
||||
uint64_t dependency_id; /* Grayout if value of lb_cfr_numeric_option with given ID is 0.
|
||||
* Ignore if field is 0.
|
||||
*/
|
||||
uint32_t flags; /* enum cfr_option_flags */
|
||||
/*
|
||||
* struct lb_cfr_varbinary default_value
|
||||
* struct lb_cfr_varbinary opt_name
|
||||
* struct lb_cfr_varbinary ui_name
|
||||
* struct lb_cfr_varbinary ui_helptext (Optional)
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* A CFR option comment is roughly equivalent to a Kconfig comment.
|
||||
* Option comments are *NOT* string options (see CFR_OPTION_VARCHAR
|
||||
* instead) but they're considered an option for simplicity's sake.
|
||||
*/
|
||||
struct __packed lb_cfr_option_comment {
|
||||
uint32_t tag; /* CFR_TAG_OPTION_COMMENT */
|
||||
uint32_t size;
|
||||
uint64_t object_id; /* Uniqueue ID */
|
||||
uint64_t dependency_id; /* Grayout if value of lb_cfr_numeric_option with given ID is 0.
|
||||
* Ignore if field is 0.
|
||||
*/
|
||||
uint32_t flags; /* enum cfr_option_flags */
|
||||
/*
|
||||
* struct lb_cfr_varbinary ui_name
|
||||
* struct lb_cfr_varbinary ui_helptext (Optional)
|
||||
*/
|
||||
};
|
||||
|
||||
/* CFR forms are considered options as they can be nested inside other forms */
|
||||
struct __packed lb_cfr_option_form {
|
||||
uint32_t tag; /* CFR_TAG_OPTION_FORM */
|
||||
uint32_t size;
|
||||
uint64_t object_id; /* Uniqueue ID */
|
||||
uint64_t dependency_id; /* Grayout if value of lb_cfr_numeric_option with given ID is 0.
|
||||
* Ignore if field is 0.
|
||||
*/
|
||||
uint32_t flags; /* enum cfr_option_flags */
|
||||
/*
|
||||
* struct lb_cfr_varbinary ui_name
|
||||
* struct lb_cfr_varchar_option options[]
|
||||
*/
|
||||
};
|
||||
|
||||
struct __packed lb_cfr_header {
|
||||
uint32_t tag;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
#endif /* DRIVERS_OPTION_CFR_H */
|
||||
|
|
@ -89,6 +89,7 @@ enum {
|
|||
LB_TAG_PCIE = 0x0044,
|
||||
LB_TAG_EFI_FW_INFO = 0x0045,
|
||||
LB_TAG_CAPSULE = 0x0046,
|
||||
LB_TAG_CFR_ROOT = 0x0047,
|
||||
/* The following options are CMOS-related */
|
||||
LB_TAG_CMOS_OPTION_TABLE = 0x00c8,
|
||||
LB_TAG_OPTION = 0x00c9,
|
||||
|
|
@ -598,5 +599,11 @@ struct lb_efi_fw_info {
|
|||
uint32_t lowest_supported_version; /* Lowest allowed version for downgrades */
|
||||
uint32_t fw_size; /* Size of firmware in bytes */
|
||||
} __packed;
|
||||
struct lb_cfr {
|
||||
uint32_t tag;
|
||||
uint32_t size;
|
||||
uint32_t checksum; /* Checksum of the variable payload. */
|
||||
/* struct lb_cfr_option_form forms[] */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue