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>
3.3 KiB
CFR - coreboot form representation - Internals
This documents the API internally used by coreboot to be used by ramstage code.
Please read CFR first.
Enabling CFR support
Users should select DRIVERS_OPTION_CFR in Kconfig to enable CFR
support. Mainboards should select DRIVERS_OPTION_CFR_ENABLED to
enable DRIVERS_OPTION_CFR by default.
Using CFR
When CFR support is enabled there are two possibilites to generate the records:
- mainboard specific code
- automatic collection
In both cases you have to add C structs in ramstage to describe the
option and group them together into a form. CFR objects should reside
on the heap as they can be modified to match the current boot flow.
Updating CFR options
The CFR options should be updated before tables are written.
You can use a callback, using the WITH_CALLBACK() macro, to update
single or multiple options when the CFR table is written into the
coreboot table.
Example: Updates the option serial_number with the contents from the EMI eeprom.
static void update_serial(const struct sm_object *obj, struct sm_object *new)
{
new->sm_varchar.default_value = get_emi_eeprom_vpd()->serial_number;
}
static const struct sm_object serial_number = SM_DECLARE_VARCHAR({
.flags = CFR_OPTFLAG_READONLY | CFR_OPTFLAG_VOLATILE,
.opt_name = "serial_number",
.ui_name = "Serial Number",
}, WITH_CALLBACK(update_serial));
Dependencies in CFR options
The CFR options can have a dependency that must be evaluated at runtime by
the OS/payload that parses the CFR record and displays the UI.
By using the WITH_DEP() macro you can specify another numberic option that
is checked to hide the current option.
Example: Declares a dependency from sata_disable_port0 to sata_enable.
The option sata_disable_port0 will be hidden as long as "sata_enable" is 0.
When the user changes "sata_enable" to 1 or it was 1 then the option
sata_disable_port0 should be visible.
static struct sm_object sata_enable = SM_DECLARE_BOOL({
.flags = CFR_OPTFLAG_RUNTIME,
.opt_name = "sata_enable",
.ui_name = "Enable SATA controller",
.ui_helptext = NULL,
.default_value = true,
});
static struct sm_object sata_disable_port0 = SM_DECLARE_BOOL({
.flags = CFR_OPTFLAG_RUNTIME,
.opt_name = "sata_disable_port0",
.ui_name = "Disable SATA port #0",
.ui_helptext = NULL,
.default_value = false,
}, WITH_DEP(&sata_enable));
Providing mainboard custom options
A mainboard that uses CFR can provide a list of custom options
be overwriting the weak void mb_cfr_setup_menu(struct lb_cfr *cfr_root);
function in ramstage.
Automatic CFR collection
CFR forms that have the __cfr_form attribute are automatically collected
and inserted into the coreboot table.
Example
The following CFR form southbridge will be automatically added to the
coreboot table and it will have a single option called Enable NMI that
allows the variable nmi to be changed to 0 or 1.
Example:
static struct sm_object nmi = SM_DECLARE_BOOL({
.flags = CFR_OPTFLAG_RUNTIME,
.opt_name = "nmi",
.ui_name = "Enable NMI",
.ui_helptext = NULL,
.default_value = false,
});
static const __cfr_form struct sm_obj_form southbridge = {
.flags = 0,
.ui_name = "Southbridge",
.obj_list = (const struct sm_object *[]) {
&nmi,
NULL
},
};