diff --git a/Documentation/drivers/cfr.md b/Documentation/drivers/cfr.md index ade6d2b14a3..0405f5c58c7 100644 --- a/Documentation/drivers/cfr.md +++ b/Documentation/drivers/cfr.md @@ -26,7 +26,7 @@ visible name, a help text, a default value and status flags. All strings are in ASCII. The boot options are grouped into forms, where each form hold -one ore more options. Boot options that are not used in the current +one or more options. Boot options that are not used in the current boot flow, and are never reachable should be marked as hidden. Dependecies between options can be defined in the code and should be evaluated by the CFR parser/UI. @@ -66,7 +66,7 @@ The public API can be found in ## Implementation design ### Tags Tags identify the structure defined in `src/commonlib/include/commonlib/cfr.h`. -Every struct might be immideatly followed by additional structs (so called +Every struct might be immediately followed by additional structs (so called sub nodes), having their own tag and size field. The sum of all sub nodes size fields plus the size of the struct itself equals the size field. @@ -208,7 +208,7 @@ effect on the non-volatile variable. Prevents writes to the variable. -* `CFR_OPTFLAG_GRAYOUT` +* `CFR_OPTFLAG_INACTIVE` Implies `READONLY`. The option is visible, but cannot be modified because one of the dependencies are not given. However there's a diff --git a/Documentation/drivers/cfr_internal.md b/Documentation/drivers/cfr_internal.md index 95fef66eee5..b2355d7b62b 100644 --- a/Documentation/drivers/cfr_internal.md +++ b/Documentation/drivers/cfr_internal.md @@ -50,8 +50,9 @@ static const struct sm_object serial_number = SM_DECLARE_VARCHAR({ 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. +By using the `WITH_DEP()` macro you can specify another numeric option that +is checked to hide the current option. The `WITH_DEP_VALUES()` macro allows +specifying one or more values that cause the dependent option to be displayed. **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. @@ -76,6 +77,37 @@ static struct sm_object sata_disable_port0 = SM_DECLARE_BOOL({ }, WITH_DEP(&sata_enable)); ``` +**Example:** Declares a dependency from `com1_termination` to `com1_mode`. +The option `com1_termination` will only be shown if `com1_mode` is set to RS-485. + +``` +#define COM_MODE_DISABLED 3 +#define COM_MODE_RS232 0 +#define COM_MODE_RS485 1 + +static struct sm_object com1_mode = SM_DECLARE_ENUM({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "com1_mode", + .ui_name = "COM1 Mode", + .ui_helptext = NULL, + .default_value = 1, + .values = (const struct sm_enum_value[]) { + { "Disabled", COM_MODE_DISABLED }, + { "RS-232", COM_MODE_RS232 }, + { "RS-485", COM_MODE_RS485 }, + SM_ENUM_VALUE_END }, +}); + +static struct sm_object com1_termination = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "com1_termination", + .ui_name = "Enable COM1 termination resistors", + .ui_helptext = NULL, + .default_value = false, +}, WITH_DEP_VALUES(&com1_mode, COM_MODE_RS485)); + +``` + ### Providing mainboard custom options A mainboard that uses CFR can provide a list of custom options diff --git a/configs/config.lenovo_m900_tiny b/configs/config.lenovo_m900_tiny new file mode 100644 index 00000000000..5bc8609d66a --- /dev/null +++ b/configs/config.lenovo_m900_tiny @@ -0,0 +1,49 @@ +CONFIG_CCACHE=y +CONFIG_VENDOR_LENOVO=y +CONFIG_VBOOT=y +CONFIG_VBOOT_SLOTS_RW_A=y +CONFIG_VBOOT_NO_BOARD_SUPPORT=y +CONFIG_BOARD_LENOVO_THINKCENTRE_M900_TINY=y +CONFIG_TPM_MEASURED_BOOT=y +CONFIG_INTEL_ME_DISABLED_HECI=y +CONFIG_DRIVERS_EFI_VARIABLE_STORE=y +CONFIG_DRIVERS_OPTION_CFR=y +CONFIG_CBFS_VERIFICATION=y +CONFIG_VBOOT_CBFS_INTEGRATION=y +CONFIG_VBOOT_MOCK_SECDATA=y +CONFIG_VBOOT_CLEAR_RECOVERY_IN_RAMSTAGE=y +CONFIG_TPM2=y +CONFIG_TPM_HASH_SHA256=y +CONFIG_BOOTMEDIA_LOCK_CONTROLLER=y +CONFIG_BOOTMEDIA_LOCK_WPRO_VBOOT_RO=y +CONFIG_BOOTMEDIA_LOCK_IN_VERSTAGE=y +CONFIG_BOOTMEDIA_SMM_BWP=y +CONFIG_DEFAULT_CONSOLE_LOGLEVEL_0=y +CONFIG_PAYLOAD_EDK2=y +CONFIG_EDK2_REPOSITORY="https://github.com/Dasharo/edk2.git" +CONFIG_EDK2_TAG_OR_REV="origin/cfr_ng" +CONFIG_EDK2_USE_EDK2_PLATFORMS=y +CONFIG_EDK2_PLATFORMS_REPOSITORY="https://github.com/Dasharo/edk2-platforms" +CONFIG_EDK2_PLATFORMS_TAG_OR_REV="3323ed481d35096fb6a7eae7b49f35eff00f86cf" +CONFIG_EDK2_CBMEM_LOGGING=y +CONFIG_EDK2_FOLLOW_BGRT_SPEC=y +CONFIG_EDK2_SERIAL_SUPPORT=y +CONFIG_EDK2_CUSTOM_BUILD_PARAMS="--pcd gDasharoSystemFeaturesTokenSpaceGuid.PcdShowMenu=FALSE" +CONFIG_BUILD_IPXE=y +CONFIG_EDK2_ENABLE_IPXE=y +# CONFIG_EDK2_SECURE_BOOT_DEFAULT_ENABLE is not set +CONFIG_EDK2_PERFORMANCE_MEASUREMENT_ENABLE=y +CONFIG_EDK2_DASHARO_SYSTEM_FEATURES=y +CONFIG_EDK2_DASHARO_SECURITY_OPTIONS=y +CONFIG_EDK2_DASHARO_INTEL_ME_OPTIONS=y +CONFIG_EDK2_DASHARO_USB_CONFIG=y +CONFIG_EDK2_DASHARO_NETWORK_CONFIG=y +CONFIG_EDK2_DASHARO_NETWORK_BOOT_DEFAULT_ENABLE=y +CONFIG_EDK2_DASHARO_SERIAL_REDIRECTION_DEFAULT_ENABLE=y +CONFIG_EDK2_DASHARO_CPU_CONFIG=y +CONFIG_EDK2_HYPERTHREADING_OPTION=y +CONFIG_EDK2_DISABLE_OPTION_ROMS=y +CONFIG_EDK2_CREATE_PREINSTALLED_BOOT_OPTIONS=y +CONFIG_EDK2_USE_UEFIVAR_BACKED_TPM_PPI=y +CONFIG_EDK2_ENABLE_FAST_BOOT_FEATURE=y +CONFIG_EDK2_ENABLE_QUIET_BOOT_FEATURE=y diff --git a/src/commonlib/include/commonlib/cfr.h b/src/commonlib/include/commonlib/cfr.h index 22058e96f91..af68269e297 100644 --- a/src/commonlib/include/commonlib/cfr.h +++ b/src/commonlib/include/commonlib/cfr.h @@ -49,6 +49,8 @@ * */ +#define CFR_VERSION 0x00000000 + enum cfr_tags { CFR_TAG_OPTION_FORM = 1, CFR_TAG_ENUM_VALUE = 2, @@ -61,6 +63,7 @@ enum cfr_tags { CFR_TAG_VARCHAR_UI_HELPTEXT = 9, CFR_TAG_VARCHAR_DEF_VALUE = 10, CFR_TAG_OPTION_COMMENT = 11, + CFR_TAG_DEP_VALUES = 12, }; /* @@ -68,7 +71,7 @@ enum cfr_tags { * effect on the non-volatile variable. * CFR_OPTFLAG_READONLY: * Prevents writes to the variable. - * CFR_OPTFLAG_GRAYOUT: + * CFR_OPTFLAG_INACTIVE: * 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. @@ -93,7 +96,7 @@ enum cfr_tags { */ 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, @@ -102,7 +105,8 @@ enum cfr_option_flags { 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 + * CFR_TAG_VARCHAR_UI_HELPTEXT, CFR_TAG_VARCHAR_DEF_VALUE + * or CFR_TAG_DEP_VALUES */ uint32_t size; /* Length of the entire structure */ uint32_t data_length; /* Length of data, including NULL terminator for strings */ @@ -117,6 +121,15 @@ struct __packed lb_cfr_enum_value { */ }; +/* + * The optional flags describe how a numeric option is to be displayed. + * CFR_NUM_OPT_DISPFLAG_HEX: + * Displays a NUMBER option in hexadecimal instead of decimal notation. + */ +enum cfr_numeric_option_display_flags { + CFR_NUM_OPT_DISPFLAG_HEX = 1 << 0, +}; + /* Supports multiple option types: ENUM, NUMBER, BOOL */ struct __packed lb_cfr_numeric_option { uint32_t tag; /* @@ -130,10 +143,16 @@ struct __packed lb_cfr_numeric_option { */ uint32_t flags; /* enum cfr_option_flags */ uint32_t default_value; + uint32_t min; + uint32_t max; + uint32_t step; + uint32_t display_flags; /* enum cfr_numeric_option_display_flags */ + /* * struct lb_cfr_varbinary opt_name * struct lb_cfr_varbinary ui_name * struct lb_cfr_varbinary ui_helptext (Optional) + * struct lb_cfr_varbinary dependency_values (Optional) * struct lb_cfr_enum_value enum_values[] */ }; @@ -151,6 +170,7 @@ struct __packed lb_cfr_varchar_option { * struct lb_cfr_varbinary opt_name * struct lb_cfr_varbinary ui_name * struct lb_cfr_varbinary ui_helptext (Optional) + * struct lb_cfr_varbinary dependency_values (Optional) */ }; @@ -170,6 +190,7 @@ struct __packed lb_cfr_option_comment { /* * struct lb_cfr_varbinary ui_name * struct lb_cfr_varbinary ui_helptext (Optional) + * struct lb_cfr_varbinary dependency_values (Optional) */ }; @@ -184,6 +205,7 @@ struct __packed lb_cfr_option_form { uint32_t flags; /* enum cfr_option_flags */ /* * struct lb_cfr_varbinary ui_name + * struct lb_cfr_varbinary dependency_values (Optional) * struct lb_cfr_varchar_option options[] */ }; diff --git a/src/commonlib/include/commonlib/coreboot_tables.h b/src/commonlib/include/commonlib/coreboot_tables.h index 6740781603d..0d42b50783d 100644 --- a/src/commonlib/include/commonlib/coreboot_tables.h +++ b/src/commonlib/include/commonlib/coreboot_tables.h @@ -603,6 +603,7 @@ struct lb_efi_fw_info { struct lb_cfr { uint32_t tag; uint32_t size; + uint32_t version; uint32_t checksum; /* Checksum of the variable payload. */ /* struct lb_cfr_option_form forms[] */ }; diff --git a/src/drivers/option/cfr.c b/src/drivers/option/cfr.c index b323b4318a7..26bdd55f4d2 100644 --- a/src/drivers/option/cfr.c +++ b/src/drivers/option/cfr.c @@ -29,9 +29,6 @@ static uint32_t cfr_record_size(const char *startp, const char *endp) static uint32_t write_cfr_varchar(char *current, const char *string, uint32_t tag) { - uint8_t *data; - size_t padding; - ASSERT(string); if (!string) return 0; @@ -72,6 +69,25 @@ static uint32_t sm_write_ui_helptext(char *current, const char *string) return write_cfr_varchar(current, string, CFR_TAG_VARCHAR_UI_HELPTEXT); } +static uint32_t sm_write_dep_values(char *current, + const uint32_t *dep_values, const uint32_t num_dep_values) +{ + /* Dependency values are optional */ + if (!dep_values || !num_dep_values) + return 0; + + struct lb_cfr_varbinary *cfr_values = (struct lb_cfr_varbinary *)current; + cfr_values->tag = CFR_TAG_DEP_VALUES; + cfr_values->data_length = sizeof(*dep_values) * num_dep_values; + char *data = current + sizeof(*cfr_values); + memcpy(data, dep_values, cfr_values->data_length); + + /* Make sure that every TAG/SIZE field is always aligned to LB_ENTRY_ALIGN */ + cfr_values->size = ALIGN_UP(sizeof(*cfr_values) + cfr_values->data_length, LB_ENTRY_ALIGN); + + return cfr_values->size; +} + static uint32_t sm_write_enum_value(char *current, const struct sm_enum_value *e) { struct lb_cfr_enum_value *enum_val = (struct lb_cfr_enum_value *)current; @@ -88,8 +104,9 @@ static uint32_t sm_write_enum_value(char *current, const struct sm_enum_value *e static uint32_t write_numeric_option(char *current, uint32_t tag, const uint64_t object_id, const char *opt_name, const char *ui_name, const char *ui_helptext, - uint32_t flags, uint32_t default_value, const struct sm_enum_value *values, - const uint64_t dep_id) + uint32_t flags, uint32_t default_value, uint32_t min, uint32_t max, uint32_t step, + uint32_t display_flags, const struct sm_enum_value *values, const uint64_t dep_id, + const uint32_t *dep_values, const uint32_t num_dep_values) { struct lb_cfr_numeric_option *option = (struct lb_cfr_numeric_option *)current; size_t len; @@ -98,9 +115,13 @@ static uint32_t write_numeric_option(char *current, uint32_t tag, const uint64_t option->object_id = object_id; option->dependency_id = dep_id; option->flags = flags; - if (option->flags & (CFR_OPTFLAG_GRAYOUT | CFR_OPTFLAG_VOLATILE)) + if (option->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE)) option->flags |= CFR_OPTFLAG_READONLY; option->default_value = default_value; + option->min = (min <= max) ? min : 0; + option->max = (min == 0 && max == 0) ? UINT32_MAX : max; + option->step = step; + option->display_flags = display_flags; option->size = sizeof(*option); current += option->size; @@ -113,6 +134,7 @@ static uint32_t write_numeric_option(char *current, uint32_t tag, const uint64_t return 0; current += len; current += sm_write_ui_helptext(current, ui_helptext); + current += sm_write_dep_values(current, dep_values, num_dep_values); if (option->tag == CFR_TAG_OPTION_ENUM && values) { for (const struct sm_enum_value *e = values; e->ui_name; e++) { @@ -125,35 +147,42 @@ static uint32_t write_numeric_option(char *current, uint32_t tag, const uint64_t } static uint32_t sm_write_opt_enum(char *current, const struct sm_obj_enum *sm_enum, - const uint64_t object_id, const uint64_t dep_id) + const uint64_t object_id, const uint64_t dep_id, + const uint32_t *dep_values, const uint32_t num_dep_values) { return write_numeric_option(current, CFR_TAG_OPTION_ENUM, object_id, sm_enum->opt_name, sm_enum->ui_name, sm_enum->ui_helptext, - sm_enum->flags, sm_enum->default_value, sm_enum->values, - dep_id); + sm_enum->flags, sm_enum->default_value, 0, 0, 0, 0, sm_enum->values, + dep_id, dep_values, num_dep_values); } static uint32_t sm_write_opt_number(char *current, const struct sm_obj_number *sm_number, - const uint64_t object_id, const uint64_t dep_id) + const uint64_t object_id, const uint64_t dep_id, + const uint32_t *dep_values, const uint32_t num_dep_values) { return write_numeric_option(current, CFR_TAG_OPTION_NUMBER, object_id, sm_number->opt_name, sm_number->ui_name, sm_number->ui_helptext, - sm_number->flags, sm_number->default_value, NULL, dep_id); + sm_number->flags, sm_number->default_value, sm_number->min, sm_number->max, + sm_number->step, sm_number->display_flags, NULL, dep_id, dep_values, + num_dep_values); } static uint32_t sm_write_opt_bool(char *current, const struct sm_obj_bool *sm_bool, - const uint64_t object_id, const uint64_t dep_id) + const uint64_t object_id, const uint64_t dep_id, + const uint32_t *dep_values, const uint32_t num_dep_values) { return write_numeric_option(current, CFR_TAG_OPTION_BOOL, object_id, sm_bool->opt_name, sm_bool->ui_name, sm_bool->ui_helptext, - sm_bool->flags, sm_bool->default_value, NULL, dep_id); + sm_bool->flags, sm_bool->default_value, 0, 0, 0, 0, NULL, dep_id, + dep_values, num_dep_values); } static uint32_t sm_write_opt_varchar(char *current, const struct sm_obj_varchar *sm_varchar, - const uint64_t object_id, const uint64_t dep_id) + const uint64_t object_id, const uint64_t dep_id, + const uint32_t *dep_values, const uint32_t num_dep_values) { struct lb_cfr_varchar_option *option = (struct lb_cfr_varchar_option *)current; @@ -163,7 +192,7 @@ static uint32_t sm_write_opt_varchar(char *current, const struct sm_obj_varchar option->object_id = object_id; option->dependency_id = dep_id; option->flags = sm_varchar->flags; - if (option->flags & (CFR_OPTFLAG_GRAYOUT | CFR_OPTFLAG_VOLATILE)) + if (option->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE)) option->flags |= CFR_OPTFLAG_READONLY; option->size = sizeof(*option); @@ -178,13 +207,15 @@ static uint32_t sm_write_opt_varchar(char *current, const struct sm_obj_varchar return 0; current += len; current += sm_write_ui_helptext(current, sm_varchar->ui_helptext); + current += sm_write_dep_values(current, dep_values, num_dep_values); option->size = cfr_record_size((char *)option, current); return option->size; } static uint32_t sm_write_opt_comment(char *current, const struct sm_obj_comment *sm_comment, - const uint32_t object_id, const uint32_t dep_id) + const uint32_t object_id, const uint32_t dep_id, + const uint32_t *dep_values, const uint32_t num_dep_values) { struct lb_cfr_option_comment *comment = (struct lb_cfr_option_comment *)current; size_t len; @@ -193,7 +224,7 @@ static uint32_t sm_write_opt_comment(char *current, const struct sm_obj_comment comment->object_id = object_id; comment->dependency_id = dep_id; comment->flags = sm_comment->flags; - if (comment->flags & (CFR_OPTFLAG_GRAYOUT | CFR_OPTFLAG_VOLATILE)) + if (comment->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE)) comment->flags |= CFR_OPTFLAG_READONLY; comment->size = sizeof(*comment); @@ -203,6 +234,7 @@ static uint32_t sm_write_opt_comment(char *current, const struct sm_obj_comment return 0; current += len; current += sm_write_ui_helptext(current, sm_comment->ui_helptext); + current += sm_write_dep_values(current, dep_values, num_dep_values); comment->size = cfr_record_size((char *)comment, current); return comment->size; @@ -218,7 +250,8 @@ static uint64_t sm_gen_obj_id(void *ptr) static uint32_t sm_write_object(char *current, const struct sm_object *sm_obj); static uint32_t sm_write_form(char *current, struct sm_obj_form *sm_form, - const uint64_t object_id, const uint64_t dep_id) + const uint64_t object_id, const uint64_t dep_id, + const uint32_t *dep_values, const uint32_t num_dep_values) { struct lb_cfr_option_form *form = (struct lb_cfr_option_form *)current; size_t len; @@ -228,7 +261,7 @@ static uint32_t sm_write_form(char *current, struct sm_obj_form *sm_form, form->object_id = object_id; form->dependency_id = dep_id; form->flags = sm_form->flags; - if (form->flags & (CFR_OPTFLAG_GRAYOUT | CFR_OPTFLAG_VOLATILE)) + if (form->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE)) form->flags |= CFR_OPTFLAG_READONLY; form->size = sizeof(*form); @@ -237,6 +270,7 @@ static uint32_t sm_write_form(char *current, struct sm_obj_form *sm_form, if (!len) return 0; current += len; + current += sm_write_dep_values(current, dep_values, num_dep_values); while (sm_form->obj_list[i]) current += sm_write_object(current, sm_form->obj_list[i++]); @@ -248,6 +282,8 @@ static uint32_t sm_write_form(char *current, struct sm_obj_form *sm_form, static uint32_t sm_write_object(char *current, const struct sm_object *sm_obj) { uint64_t dep_id, obj_id; + const uint32_t *dep_values; + uint32_t num_dep_values; struct sm_object sm_obj_copy; assert(sm_obj); @@ -256,10 +292,14 @@ static uint32_t sm_write_object(char *current, const struct sm_object *sm_obj) /* Set dependency ID */ dep_id = 0; + dep_values = NULL; + num_dep_values = 0; if (sm_obj->dep) { - assert(sm_obj->dep->kind == SM_OBJ_BOOL); - if (sm_obj->dep->kind == SM_OBJ_BOOL) + if (sm_obj->dep->kind == SM_OBJ_BOOL || sm_obj->dep->kind == SM_OBJ_ENUM) { dep_id = sm_gen_obj_id((void *)sm_obj->dep); + dep_values = sm_obj->dep_values; + num_dep_values = sm_obj->num_dep_values; + } } /* Invoke callback to update fields */ @@ -276,21 +316,22 @@ static uint32_t sm_write_object(char *current, const struct sm_object *sm_obj) return 0; case SM_OBJ_ENUM: return sm_write_opt_enum(current, &sm_obj->sm_enum, obj_id, - dep_id); + dep_id, dep_values, num_dep_values); case SM_OBJ_NUMBER: return sm_write_opt_number(current, &sm_obj->sm_number, obj_id, - dep_id); + dep_id, dep_values, num_dep_values); case SM_OBJ_BOOL: return sm_write_opt_bool(current, &sm_obj->sm_bool, obj_id, - dep_id); + dep_id, dep_values, num_dep_values); case SM_OBJ_VARCHAR: return sm_write_opt_varchar(current, &sm_obj->sm_varchar, obj_id, - dep_id); + dep_id, dep_values, num_dep_values); case SM_OBJ_COMMENT: return sm_write_opt_comment(current, &sm_obj->sm_comment, obj_id, - dep_id); + dep_id, dep_values, num_dep_values); case SM_OBJ_FORM: - return sm_write_form(current, (struct sm_obj_form *)&sm_obj->sm_form, obj_id, dep_id); + return sm_write_form(current, (struct sm_obj_form *)&sm_obj->sm_form, obj_id, + dep_id, dep_values, num_dep_values); default: BUG(); printk(BIOS_ERR, "Unknown setup menu object kind %u, ignoring\n", sm_obj->kind); @@ -310,16 +351,17 @@ void cfr_write_setup_menu(struct lb_cfr *cfr_root, struct sm_obj_form *sm_root[] cfr_root->tag = LB_TAG_CFR_ROOT; cfr_root->size = sizeof(*cfr_root); + cfr_root->version = CFR_VERSION; current += cfr_root->size; while (sm_root && sm_root[i]) - current += sm_write_form(current, sm_root[i++], 0, 0); + current += sm_write_form(current, sm_root[i++], 0, 0, NULL, 0); /* * Add generic forms. */ for (obj = &_cfr_forms[0]; obj != &_ecfr_forms[0]; obj++) - current += sm_write_form(current, obj, 0, 0); + current += sm_write_form(current, obj, 0, 0, NULL, 0); cfr_root->size = cfr_record_size((char *)cfr_root, current); diff --git a/src/drivers/option/cfr_frontend.h b/src/drivers/option/cfr_frontend.h index 2161853f010..17332bdca44 100644 --- a/src/drivers/option/cfr_frontend.h +++ b/src/drivers/option/cfr_frontend.h @@ -30,6 +30,10 @@ struct sm_obj_number { const char *ui_name; const char *ui_helptext; uint32_t default_value; + uint32_t min; + uint32_t max; + uint32_t step; + uint32_t display_flags; /* enum cfr_numeric_option_display_flags */ }; struct sm_obj_bool { @@ -75,6 +79,8 @@ enum sm_object_kind { struct sm_object { enum sm_object_kind kind; const struct sm_object *dep; + const uint32_t *dep_values; + const uint32_t num_dep_values; void (*ctor)(const struct sm_object *obj, struct sm_object *new); /* Called on object creation */ union { struct sm_obj_enum sm_enum; @@ -87,21 +93,31 @@ struct sm_object { }; /* sm_object helpers with type checking */ -#define SM_DECLARE_ENUM(...) { .kind = SM_OBJ_ENUM, .dep = NULL, \ +#define SM_DECLARE_ENUM(...) { .kind = SM_OBJ_ENUM, .dep = NULL, \ + .dep_values = NULL, .num_dep_values = 0, \ .ctor = NULL, .sm_enum = __VA_ARGS__ } -#define SM_DECLARE_NUMBER(...) { .kind = SM_OBJ_NUMBER, .dep = NULL, \ +#define SM_DECLARE_NUMBER(...) { .kind = SM_OBJ_NUMBER, .dep = NULL, \ + .dep_values = NULL, .num_dep_values = 0, \ .ctor = NULL, .sm_number = __VA_ARGS__ } -#define SM_DECLARE_BOOL(...) { .kind = SM_OBJ_BOOL, .dep = NULL, \ +#define SM_DECLARE_BOOL(...) { .kind = SM_OBJ_BOOL, .dep = NULL, \ + .dep_values = NULL, .num_dep_values = 0, \ .ctor = NULL, .sm_bool = __VA_ARGS__ } -#define SM_DECLARE_VARCHAR(...) { .kind = SM_OBJ_VARCHAR, .dep = NULL, \ +#define SM_DECLARE_VARCHAR(...) { .kind = SM_OBJ_VARCHAR, .dep = NULL, \ + .dep_values = NULL, .num_dep_values = 0, \ .ctor = NULL, .sm_varchar = __VA_ARGS__ } -#define SM_DECLARE_COMMENT(...) { .kind = SM_OBJ_COMMENT, .dep = NULL, \ +#define SM_DECLARE_COMMENT(...) { .kind = SM_OBJ_COMMENT, .dep = NULL, \ + .dep_values = NULL, .num_dep_values = 0, \ .ctor = NULL, .sm_comment = __VA_ARGS__ } -#define SM_DECLARE_FORM(...) { .kind = SM_OBJ_FORM, .dep = NULL, \ +#define SM_DECLARE_FORM(...) { .kind = SM_OBJ_FORM, .dep = NULL, \ + .dep_values = NULL, .num_dep_values = 0, \ .ctor = NULL, .sm_form = __VA_ARGS__ } #define WITH_CALLBACK(c) .ctor = (c) #define WITH_DEP(d) .dep = (d) +#define WITH_DEP_VALUES(d, ...) \ + .dep = (d), \ + .dep_values = ((const uint32_t[]) { __VA_ARGS__ }), \ + .num_dep_values = sizeof((uint32_t[]) { __VA_ARGS__ }) / sizeof(uint32_t) void cfr_write_setup_menu(struct lb_cfr *cfr_root, struct sm_obj_form *sm_root[]); diff --git a/src/mainboard/lenovo/m900_tiny/Kconfig b/src/mainboard/lenovo/m900_tiny/Kconfig index 8ad36e0014a..334957514b0 100644 --- a/src/mainboard/lenovo/m900_tiny/Kconfig +++ b/src/mainboard/lenovo/m900_tiny/Kconfig @@ -38,4 +38,15 @@ config PRERAM_CBMEM_CONSOLE_SIZE config DIMM_SPD_SIZE default 512 #DDR4 +config VBOOT + select GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC + select GBB_FLAG_DISABLE_FWMP + select GBB_FLAG_DISABLE_LID_SHUTDOWN + select GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC + select HAS_RECOVERY_MRC_CACHE + select VBOOT_VBNV_FLASH + +config FMDFILE + default "src/mainboard/\$(CONFIG_MAINBOARD_DIR)/vboot-rwa.fmd" if VBOOT + endif diff --git a/src/mainboard/lenovo/m900_tiny/Makefile.mk b/src/mainboard/lenovo/m900_tiny/Makefile.mk index 44db0910ed2..072d9ed81f3 100644 --- a/src/mainboard/lenovo/m900_tiny/Makefile.mk +++ b/src/mainboard/lenovo/m900_tiny/Makefile.mk @@ -10,4 +10,5 @@ romstage-y += romstage.c ramstage-y += gpio.c ramstage-y += hda_verb.c ramstage-y += ramstage.c +ramstage-y += cfr.c ramstage-$(CONFIG_MAINBOARD_USE_LIBGFXINIT) += gma-mainboard.ads diff --git a/src/mainboard/lenovo/m900_tiny/cfr.c b/src/mainboard/lenovo/m900_tiny/cfr.c new file mode 100644 index 00000000000..9cd0163853a --- /dev/null +++ b/src/mainboard/lenovo/m900_tiny/cfr.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include + +struct sm_object wifi_slot_enable = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "wifi_slot_enable", + .ui_name = "Enable Wi-Fi card slot", + .ui_helptext = "Enable or disable detection of devices in the Wi-Fi card slot", + .default_value = true, +}); + +struct sm_object ssd_slot_enable = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "ssd_slot_enable", + .ui_name = "Enable SSD slot", + .ui_helptext = "Enable or disable detection of devices in the SSD slot", + .default_value = true, +}); + +struct sm_object hdd_slot_enable = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "hdd_slot_enable", + .ui_name = "Enable 2.5 inch disk slot", + .ui_helptext = "Enable or disable detection of devices in the 2.5 inch disk slot", + .default_value = true, +}); + +static struct sm_obj_form devices = { + .ui_name = "Devices", + .obj_list = (const struct sm_object *[]) { + &wifi_slot_enable, + &ssd_slot_enable, + &hdd_slot_enable, + NULL + }, +}; + +static struct sm_obj_form security = { + .ui_name = "Security", + .obj_list = (const struct sm_object *[]) { + &lock_bios, + &smm_bwp, + NULL + }, +}; + +static struct sm_obj_form chipset = { + .ui_name = "Chipset", + .obj_list = (const struct sm_object *[]) { + &me_mode, + &ps2_enable, + &power_on_after_fail, + NULL + }, +}; + +static struct sm_obj_form processor = { + .ui_name = "Processor", + .obj_list = (const struct sm_object *[]) { + &hyper_threading, + &throttle_offset, + &throttle_temp, + NULL + }, +}; + +static struct sm_obj_form bootloader = { + .ui_name = "Bootloader", + .obj_list = (const struct sm_object *[]) { + &network_boot, + &uefi_usb_stack, + &uefi_usb_msc, + &com0_redirection, + NULL + }, +}; + +static struct sm_obj_form *sm_root[] = { + &security, + &processor, + &chipset, + &devices, + &bootloader, + NULL +}; + +void mb_cfr_setup_menu(struct lb_cfr *cfr_root) +{ + cfr_write_setup_menu(cfr_root, sm_root); +} diff --git a/src/mainboard/lenovo/m900_tiny/ramstage.c b/src/mainboard/lenovo/m900_tiny/ramstage.c index 6e66f3a7cc7..d2392cc1faf 100644 --- a/src/mainboard/lenovo/m900_tiny/ramstage.c +++ b/src/mainboard/lenovo/m900_tiny/ramstage.c @@ -2,10 +2,14 @@ #include #include +#include #include #include #include +#include #include +#include +#include static void print_board_id(void) { @@ -32,22 +36,45 @@ static void print_board_id(void) } printk(BIOS_INFO, "Serial header %spopulated\n", !gpio_get(GPP_A22) ? "" : "un"); - printk(BIOS_INFO, "PS/2 header %spopulated\n", !gpio_get(GPP_D14) ? "" : "un"); - printk(BIOS_INFO, "USB header %spopulated\n", !gpio_get(GPP_C19) ? "" : "un"); - printk(BIOS_INFO, "DisplayPort header %spopulated\n", !gpio_get(GPP_B15) ? "" : "un"); - printk(BIOS_INFO, "PCIe / SATA header %spopulated\n", !gpio_get(GPP_B21) ? "" : "un"); } -static void mainboard_enable(struct device *dev) +static void devtree_update(void) +{ + config_t *cfg = config_of_soc(); + struct device *wifi_dev = DEV_PTR(pcie_rp7); + struct device *ssd_dev = DEV_PTR(pcie_rp17); + struct device *ps2_dev = dev_find_slot_pnp(0x2e, NCT6687D_KBC); + + if (get_uint_option("wifi_slot_enable", 1) == 0) { + cfg->usb2_ports[8].enable = 0; + wifi_dev->enabled = 0; + } + + if (get_uint_option("ssd_slot_enable", 1) == 0) { + cfg->SataPortsEnable[4] = 0; + ssd_dev->enabled = 0; + } + + if (get_uint_option("hdd_slot_enable", 1) == 0) { + cfg->SataPortsEnable[0] = 0; + cfg->SataPortsEnable[1] = 0; + } + + if (get_uint_option("ps2_enable", 1) == 0) + ps2_dev->enabled = 0; +} + +static void mainboard_init(void *chip_info) { mainboard_configure_gpios(); + devtree_update(); print_board_id(); } struct chip_operations mainboard_ops = { - .enable_dev = mainboard_enable, + .init = mainboard_init, }; diff --git a/src/mainboard/lenovo/m900_tiny/vboot-ro.fmd b/src/mainboard/lenovo/m900_tiny/vboot-ro.fmd new file mode 100644 index 00000000000..40855e7c010 --- /dev/null +++ b/src/mainboard/lenovo/m900_tiny/vboot-ro.fmd @@ -0,0 +1,30 @@ +FLASH 16M { + SI_ALL 8M { + SI_DESC 4K + SI_GBE 8K + SI_ME + } + SI_BIOS 8M { + RW_MISC 2M { + UNIFIED_MRC_CACHE(PRESERVE) 128K { + RECOVERY_MRC_CACHE 64K + RW_MRC_CACHE 64K + } + SMMSTORE(PRESERVE) 256K + RW_ELOG(PRESERVE) 16K + RW_SHARED 16K { + SHARED_DATA 8K + VBLOCK_DEV 8K + } + RW_NVRAM(PRESERVE) 24K + } + + WP_RO { + FMAP 2K + RO_FRID 128 + RO_PADDING 1920 + GBB 120K + COREBOOT(CBFS) + } + } +} diff --git a/src/mainboard/lenovo/m900_tiny/vboot-rwa.fmd b/src/mainboard/lenovo/m900_tiny/vboot-rwa.fmd new file mode 100644 index 00000000000..df3bfdb417b --- /dev/null +++ b/src/mainboard/lenovo/m900_tiny/vboot-rwa.fmd @@ -0,0 +1,36 @@ +FLASH 16M { + SI_ALL 8M { + SI_DESC 4K + SI_GBE 8K + SI_ME + } + SI_BIOS 8M { + RW_MISC 2M { + UNIFIED_MRC_CACHE(PRESERVE) 128K { + RECOVERY_MRC_CACHE 64K + RW_MRC_CACHE 64K + } + SMMSTORE(PRESERVE) 256K + RW_ELOG(PRESERVE) 16K + RW_SHARED 16K { + SHARED_DATA 8K + VBLOCK_DEV 8K + } + RW_NVRAM(PRESERVE) 24K + } + + RW_SECTION_A 3M { + VBLOCK_A 8K + FW_MAIN_A(CBFS) + RW_FWID_A 128 + } + + WP_RO 3M { + FMAP 2K + RO_FRID 128 + RO_PADDING 1920 + GBB 120K + COREBOOT(CBFS) + } + } +} diff --git a/src/vendorcode/dasharo/include/dasharo/cfr.h b/src/vendorcode/dasharo/include/dasharo/cfr.h new file mode 100644 index 00000000000..98fd218c9c6 --- /dev/null +++ b/src/vendorcode/dasharo/include/dasharo/cfr.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef DASHARO_CFR_H +#define DASHARO_CFR_H + +#include +#include +#include "options.h" + +struct sm_object lock_bios = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "lock_bios", + .ui_name = "Lock the BIOS boot medium", + .ui_helptext = "This option locks down the BIOS flash", + .default_value = true, +}); + +static void smm_bwp_callback(const struct sm_object *obj, struct sm_object *new) +{ + if (!CONFIG(BOOTMEDIA_SMM_BWP)) + new->sm_bool.flags |= CFR_OPTFLAG_SUPPRESS; +} + +struct sm_object smm_bwp = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "smm_bwp", + .ui_name = "SMM BIOS Write Protection", + .ui_helptext = "This option prevents flash writes outside of SMM", + .default_value = false, +}, WITH_CALLBACK(&smm_bwp_callback)); + +struct sm_object watchdog_enable = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "watchdog_enable", + .ui_name = "Enable watchdog timer", + .ui_helptext = "The watchdog will reset the platform once the timer expires", + .default_value = CONFIG(SOC_INTEL_COMMON_OC_WDT_ENABLE), +}); + +struct sm_object watchdog_timeout = SM_DECLARE_NUMBER({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "watchdog_timeout", + .ui_name = "Watchdog timeout", + .ui_helptext = "After this timeout expires, the platform will be re-set", + .default_value = CONFIG_SOC_INTEL_COMMON_OC_WDT_TIMEOUT_SECONDS, +}, WITH_DEP(&watchdog_enable)); + +struct sm_object power_on_after_fail = SM_DECLARE_ENUM({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "power_on_after_fail", + .ui_name = "Power state after fail", + .ui_helptext = "State of the platform after external power is restored", + .default_value = CONFIG_MAINBOARD_POWER_FAILURE_STATE, + .values = (const struct sm_enum_value[]) { + { "Off", 0 }, + { "On", 1 }, + { "Previous", 2 }, + SM_ENUM_VALUE_END }, +}); + +struct sm_object me_mode = SM_DECLARE_ENUM({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "me_mode", + .ui_name = "Intel ME mode", + .ui_helptext = "Operational mode of Intel Management Engine", + .default_value = CONFIG_INTEL_ME_DEFAULT_STATE, + .values = (const struct sm_enum_value[]) { + { "Enabled", ME_MODE_ENABLE }, + { "Disabled (Soft)", ME_MODE_DISABLE_HECI }, +#if CONFIG(HAVE_INTEL_ME_HAP) + { "Disabled (HAP)", ME_MODE_DISABLE_HAP }, +#endif + SM_ENUM_VALUE_END }, +}); + +static void ps2_enable_callback(const struct sm_object *obj, struct sm_object *new) +{ + if (!CONFIG(EDK2_PS2_SUPPORT)) + new->sm_bool.flags |= CFR_OPTFLAG_SUPPRESS; +} + +struct sm_object ps2_enable = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "ps2_enable", + .ui_name = "Enable PS/2 controller", + .ui_helptext = "Enable or disable the PS/2 controller. Enabling PS/2 slightly increases boot time.", + .default_value = true, +}, WITH_CALLBACK(&ps2_enable_callback)); + +struct sm_object hyper_threading = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "hyper_threading", + .ui_name = "Enable Hyper-Threading", + .ui_helptext = "Enable or disable Hyper-Threading", + .default_value = true, +}); + +struct sm_object throttle_offset = SM_DECLARE_NUMBER({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "throttle_offset", + .ui_name = "Thermal throttling offset", + .ui_helptext = "Adjust the temperature at which the processor will thermal throttle. " \ + "Lower offset means higher temperature, and vice versa.", + .default_value = CONFIG_EDK2_CPU_THROTTLING_THRESHOLD_DEFAULT, +}); + +static void update_throttling_temp(const struct sm_object *obj, struct sm_object *new) +{ + new->sm_number.default_value = CONFIG_CPU_MAX_TEMPERATURE - get_uint_option("throttle_offset", CONFIG_EDK2_CPU_THROTTLING_THRESHOLD_DEFAULT); +} + +struct sm_object throttle_temp = SM_DECLARE_NUMBER({ + .flags = CFR_OPTFLAG_READONLY | CFR_OPTFLAG_VOLATILE, + .opt_name = "throttle_temp", + .ui_name = "Current thermal throttling temperature", +}, WITH_CALLBACK(update_throttling_temp)); + + +struct sm_object network_boot = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "network_boot", + .ui_name = "Network Boot", + .ui_helptext = "Enable or disable network boot functionality", + .default_value = CONFIG(EDK2_DASHARO_NETWORK_BOOT_DEFAULT_ENABLE), +}); + +struct sm_object uefi_usb_stack = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "uefi_usb_stack", + .ui_name = "UEFI USB stack", + .ui_helptext = "Enable or disable UEFI USB Stack", + .default_value = true, +}); + +struct sm_object uefi_usb_msc = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "uefi_usb_msc", + .ui_name = "UEFI USB Mass Storage driver", + .ui_helptext = "Enable or disable UEFI USB Mass Storage driver", + .default_value = true, +}, WITH_DEP(&uefi_usb_stack)); + +struct sm_object com0_redirection = SM_DECLARE_BOOL({ + .flags = CFR_OPTFLAG_RUNTIME, + .opt_name = "com0_redirection", + .ui_name = "COM0 Console Redirection", + .ui_helptext = "Enable or disable console on COM0 serial port", + .default_value = true, +}); + +#endif // DASHARO_CFG_H diff --git a/src/vendorcode/dasharo/options.c b/src/vendorcode/dasharo/options.c index a4583b574fb..48aa642568a 100644 --- a/src/vendorcode/dasharo/options.c +++ b/src/vendorcode/dasharo/options.c @@ -189,7 +189,9 @@ bool is_vboot_locking_permitted(void) if (CONFIG(DASHARO_FIRMWARE_UPDATE_MODE) && fum) return false; - if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) + if (CONFIG(DRIVERS_OPTION_CFR)) + lock = get_uint_option("lock_bios", false); + else if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) read_bool_var("LockBios", &lock); return lock; @@ -265,7 +267,9 @@ uint8_t cse_get_me_disable_mode(void) uint8_t var = CONFIG_INTEL_ME_DEFAULT_STATE; bool fum = false; - if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) { + if (CONFIG(DRIVERS_OPTION_CFR)) { + var = get_uint_option("me_mode", CONFIG_INTEL_ME_DEFAULT_STATE); + } else if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) { read_bool_var("FirmwareUpdateMode", &fum); read_u8_var("MeMode", &var); } @@ -320,7 +324,9 @@ bool is_smm_bwp_permitted(void) if (CONFIG(DASHARO_FIRMWARE_UPDATE_MODE) && fum) return false; - if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) + if (CONFIG(DRIVERS_OPTION_CFR)) + smm_bwp = get_uint_option("smm_bwp", false); + else if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) read_bool_var("SmmBwp", &smm_bwp); else return CONFIG(BOOTMEDIA_SMM_BWP); @@ -341,9 +347,14 @@ void get_watchdog_config(struct watchdog_config *wdt_cfg) return; size = sizeof(*wdt_cfg); - if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) + if (CONFIG(DRIVERS_OPTION_CFR)) { + wdt_cfg->wdt_enable = get_uint_option("watchdog_enable", CONFIG(SOC_INTEL_COMMON_OC_WDT_ENABLE)); + wdt_cfg->wdt_timeout = get_uint_option("watchdog_timeout", CONFIG_SOC_INTEL_COMMON_OC_WDT_TIMEOUT_SECONDS); + ret = CB_SUCCESS; + } else if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) { ret = efi_fv_get_option(&rdev, &dasharo_system_features_guid, "WatchdogConfig", wdt_cfg, &size); + } if (ret != CB_SUCCESS || size != sizeof(*wdt_cfg)) { wdt_cfg->wdt_enable = CONFIG(SOC_INTEL_COMMON_OC_WDT_ENABLE); @@ -355,7 +366,9 @@ bool get_ps2_option(void) { bool ps2_en = true; - if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) + if (CONFIG(DRIVERS_OPTION_CFR)) + ps2_en = get_uint_option("ps2_enable", true); + else if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) read_bool_var("Ps2Controller", &ps2_en); return ps2_en; @@ -530,7 +543,9 @@ uint8_t get_cpu_throttling_offset(uint8_t tcc_offset) { uint8_t offset = tcc_offset; - if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) + if (CONFIG(DRIVERS_OPTION_CFR)) + offset = get_uint_option("throttle_offset", tcc_offset); + else if (CONFIG(DRIVERS_EFI_VARIABLE_STORE)) read_u8_var("CpuThrottlingOffset", &offset); return offset;