[PATCH v7 0/3] firmware: Add coreboot CFR firmware attributes driver
From: Sean Rhodes
Date: Fri Jul 17 2026 - 04:55:41 EST
Move the firmware attributes class helper out of platform/x86, rename
the coreboot-table firmware driver directory from google to coreboot, and
add a coreboot CFR firmware attributes driver.
Changes in v7:
- Restore the existing include order in converted platform/x86 drivers
and add Oliver's Tested-by to patch 1.
- Use for loops for the CFR record walks, document pointer-based value
validation and intentionally ignored record types, and remove a
redundant PAGE_SIZE check.
- Validate the CFR payload checksum before parsing it.
- Make EFI writes transactional: lock the complete operation, restore
both the variable and live state on failure, and preserve a pending
reboot indication when rollback cannot fully restore the setting.
- Lock EFI reads and expose settings read-only when EFI writes are not
supported.
- Skip settings beneath suppressed or dependency-gated forms, propagate
enclosing read-only/inactive state, and bound CFR form nesting.
- Propagate transient probe failures instead of silently dropping
settings.
- Preserve APM token zero and skip an enumeration if its values cannot
fit in the sysfs output buffer.
- Simplify the device_create() error path.
Testing:
- x86_64 allmodconfig W=1 builds of the CFR driver, firmware attributes
helper, and all converted platform/x86 consumers.
- UML allmodconfig W=1 builds of the CFR driver and helper, exercising
the path compiled without CONFIG_X86.
Sean Rhodes (3):
firmware: Move firmware attributes class helper
firmware: Rename google firmware directory to coreboot
firmware: coreboot: Add CFR firmware attributes driver
MAINTAINERS | 18 +-
drivers/firmware/Kconfig | 5 +-
drivers/firmware/Makefile | 3 +-
drivers/firmware/{google => coreboot}/Kconfig | 20 +-
.../firmware/{google => coreboot}/Makefile | 1 +
drivers/firmware/{google => coreboot}/cbmem.c | 0
drivers/firmware/coreboot/coreboot-cfr.c | 1141 +++++++++++++++++
.../{google => coreboot}/coreboot_table.c | 0
.../{google => coreboot}/coreboot_table.h | 0
.../framebuffer-coreboot.c | 0
drivers/firmware/{google => coreboot}/gsmi.c | 0
.../memconsole-coreboot.c | 0
.../memconsole-x86-legacy.c | 0
.../{google => coreboot}/memconsole.c | 0
.../{google => coreboot}/memconsole.h | 6 +-
drivers/firmware/{google => coreboot}/vpd.c | 0
.../{google => coreboot}/vpd_decode.c | 0
.../{google => coreboot}/vpd_decode.h | 0
.../firmware_attributes_class.c | 2 +-
drivers/platform/x86/Kconfig | 3 -
drivers/platform/x86/Makefile | 2 -
drivers/platform/x86/asus-armoury.c | 2 +-
.../x86/dell/dell-wmi-sysman/sysman.c | 2 +-
drivers/platform/x86/hp/hp-bioscfg/bioscfg.c | 2 +-
drivers/platform/x86/lenovo/think-lmi.c | 2 +-
drivers/platform/x86/lenovo/wmi-other.c | 2 +-
drivers/platform/x86/samsung-galaxybook.c | 2 +-
.../linux/firmware_attributes.h | 6 +-
28 files changed, 1194 insertions(+), 25 deletions(-)
rename drivers/firmware/{google => coreboot}/Kconfig (82%)
rename drivers/firmware/{google => coreboot}/Makefile (92%)
rename drivers/firmware/{google => coreboot}/cbmem.c (100%)
create mode 100644 drivers/firmware/coreboot/coreboot-cfr.c
rename drivers/firmware/{google => coreboot}/coreboot_table.c (100%)
rename drivers/firmware/{google => coreboot}/coreboot_table.h (100%)
rename drivers/firmware/{google => coreboot}/framebuffer-coreboot.c (100%)
rename drivers/firmware/{google => coreboot}/gsmi.c (100%)
rename drivers/firmware/{google => coreboot}/memconsole-coreboot.c (100%)
rename drivers/firmware/{google => coreboot}/memconsole-x86-legacy.c (100%)
rename drivers/firmware/{google => coreboot}/memconsole.c (100%)
rename drivers/firmware/{google => coreboot}/memconsole.h (82%)
rename drivers/firmware/{google => coreboot}/vpd.c (100%)
rename drivers/firmware/{google => coreboot}/vpd_decode.c (100%)
rename drivers/firmware/{google => coreboot}/vpd_decode.h (100%)
rename drivers/{platform/x86 => firmware}/firmware_attributes_class.c (94%)
rename drivers/platform/x86/firmware_attributes_class.h => include/linux/firmware_attributes.h (60%)
Range-diff against v6:
1: 02edc6d05059 ! 1: c414cb12d7ac firmware: Move firmware attributes class helper
@@ Commit message
Reviewed-by: Mark Pearson <mpearson-lenovo@xxxxxxxxx>
Reviewed-by: Derek J. Clark <derekjohn.clark@xxxxxxxxx>
+ Tested-by: Oliver Lin <oliver@xxxxxxxxxxxxxxx>
Signed-off-by: Sean Rhodes <sean@starlabs.systems>
## MAINTAINERS ##
@@ drivers/platform/x86/Makefile: obj-$(CONFIG_X86_PLATFORM_DRIVERS_HP) += hp/
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
## drivers/platform/x86/asus-armoury.c ##
-@@
- #include <linux/dmi.h>
- #include <linux/err.h>
- #include <linux/errno.h>
-+#include <linux/firmware_attributes.h>
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <linux/kmod.h>
@@
#include <linux/sysfs.h>
#include "asus-armoury.h"
-#include "firmware_attributes_class.h"
++#include <linux/firmware_attributes.h>
#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
## drivers/platform/x86/dell/dell-wmi-sysman/sysman.c ##
@@
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
- #include <linux/align.h>
--#include <linux/fs.h>
- #include <linux/dmi.h>
--#include <linux/module.h>
-+#include <linux/firmware_attributes.h>
-+#include <linux/fs.h>
- #include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/nls.h>
- #include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/wmi.h>
-+
#include "dell-wmi-sysman.h"
-#include "../../firmware_attributes_class.h"
++#include <linux/firmware_attributes.h>
#define MAX_TYPES 4
--#include <linux/nls.h>
-
- struct wmi_sysman_priv wmi_priv = {
- .mutex = __MUTEX_INITIALIZER(wmi_priv.mutex),
+ #include <linux/nls.h>
## drivers/platform/x86/hp/hp-bioscfg/bioscfg.c ##
@@
-
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-+#include <linux/errno.h>
-+#include <linux/firmware_attributes.h>
- #include <linux/fs.h>
--#include <linux/module.h>
- #include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/nls.h>
- #include <linux/printk.h>
#include <linux/string.h>
#include <linux/wmi.h>
-+
#include "bioscfg.h"
-#include "../../firmware_attributes_class.h"
--#include <linux/nls.h>
--#include <linux/errno.h>
++#include <linux/firmware_attributes.h>
+ #include <linux/nls.h>
+ #include <linux/errno.h>
- MODULE_AUTHOR("Jorge Lopez <jorge.lopez2@xxxxxx>");
- MODULE_DESCRIPTION("HP BIOS Configuration Driver");
## drivers/platform/x86/lenovo/think-lmi.c ##
@@
-
- #include <linux/acpi.h>
- #include <linux/array_size.h>
-+#include <linux/dmi.h>
- #include <linux/errno.h>
-+#include <linux/firmware_attributes.h>
- #include <linux/fs.h>
- #include <linux/mutex.h>
- #include <linux/string_helpers.h>
#include <linux/types.h>
--#include <linux/dmi.h>
+ #include <linux/dmi.h>
#include <linux/wmi.h>
-#include "../firmware_attributes_class.h"
-+
++#include <linux/firmware_attributes.h>
#include "think-lmi.h"
static bool debug_support;
## drivers/platform/x86/lenovo/wmi-other.c ##
-@@
- #include <linux/container_of.h>
- #include <linux/device.h>
- #include <linux/export.h>
-+#include <linux/firmware_attributes.h>
- #include <linux/gfp_types.h>
- #include <linux/hwmon.h>
- #include <linux/idr.h>
@@
#include "wmi-capdata.h"
#include "wmi-events.h"
#include "wmi-helpers.h"
-#include "../firmware_attributes_class.h"
++#include <linux/firmware_attributes.h>
#define LENOVO_OTHER_MODE_GUID "DC2A8805-3A8C-41BA-A6F7-092E0089CD3B"
## drivers/platform/x86/samsung-galaxybook.c ##
@@
- #include <linux/acpi.h>
- #include <linux/bits.h>
- #include <linux/err.h>
-+#include <linux/firmware_attributes.h>
- #include <linux/i8042.h>
- #include <linux/init.h>
- #include <linux/input.h>
-@@
- #include <linux/sysfs.h>
#include <linux/uuid.h>
#include <linux/workqueue.h>
-+
#include <acpi/battery.h>
-#include "firmware_attributes_class.h"
++#include <linux/firmware_attributes.h>
#define DRIVER_NAME "samsung-galaxybook"
2: d5d3d1334994 = 2: 198e2d4dff44 firmware: Rename google firmware directory to coreboot
3: 7a65c6b0e631 ! 3: f4842df09f6e firmware: coreboot: Add CFR firmware attributes driver
@@ drivers/firmware/coreboot/Kconfig: config GOOGLE_COREBOOT_TABLE
+ tristate "coreboot CFR firmware attributes"
+ depends on EFI
+ depends on GOOGLE_COREBOOT_TABLE
++ select CRC32
+ select FW_ATTR_CLASS
+ help
+ This driver parses the coreboot CFR table and exposes runtime EFI
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
++#include <linux/crc32.h>
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/device-id/coreboot.h>
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+#define COREBOOT_CFR_APM_CNT_PORT 0xb2
+#define COREBOOT_CFR_APM_STS_PORT 0xb3
+#define COREBOOT_CFR_APM_APPLY_CMD 0xe3
++#define COREBOOT_CFR_MAX_FORM_DEPTH 16
+
+static efi_guid_t coreboot_cfr_guid = EFI_GUID(0xceae4c1d, 0x335b, 0x4685,
+ 0xa4, 0xa0, 0xfc, 0x4a,
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ struct list_head settings;
+ /* Serializes EFI variable writes and the matching runtime apply hook. */
+ struct mutex lock;
++ bool efi_writes_supported;
+ bool pending_reboot;
+};
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+coreboot_cfr_child_entry(const void *base, size_t len, u32 tag)
+{
+ const struct coreboot_table_entry *entry;
-+ size_t off = 0;
++ size_t off;
+
-+ while (off < len) {
++ for (off = 0; off < len; off += entry->size) {
+ if (len - off < sizeof(*entry))
+ return NULL;
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+
+ if (entry->tag == tag)
+ return entry;
-+
-+ off += entry->size;
+ }
+
+ return NULL;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ return no_free_ptr(efi_name);
+}
+
-+static int coreboot_cfr_read_value(const struct coreboot_cfr_setting *setting,
-+ u32 *value, u32 *attrs)
++static int coreboot_cfr_read_efi_value_locked(efi_char16_t *efi_name,
++ u32 *value, u32 *attrs)
+{
+ unsigned long size = sizeof(__le32);
-+ efi_char16_t *efi_name;
+ efi_status_t status;
+ __le32 data;
+ u32 attr;
+
-+ efi_name = coreboot_cfr_efi_name(setting->name);
-+ if (IS_ERR(efi_name))
-+ return PTR_ERR(efi_name);
-+
+ status = efivar_get_variable(efi_name, &coreboot_cfr_guid, &attr,
+ &size, &data);
-+ kfree(efi_name);
+ if (status != EFI_SUCCESS)
+ return efi_status_to_err(status);
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ return 0;
+}
+
-+static int coreboot_cfr_write_efi_value(struct coreboot_cfr_setting *setting,
-+ u32 value, u32 attrs)
++static int coreboot_cfr_read_value(const struct coreboot_cfr_setting *setting,
++ u32 *value, u32 *attrs)
+{
+ efi_char16_t *efi_name;
-+ efi_status_t status;
-+ __le32 data;
++ int ret;
+
+ efi_name = coreboot_cfr_efi_name(setting->name);
+ if (IS_ERR(efi_name))
+ return PTR_ERR(efi_name);
+
-+ data = cpu_to_le32(value);
-+ status = efivar_set_variable(efi_name, &coreboot_cfr_guid, attrs,
-+ sizeof(data), &data);
++ ret = efivar_lock();
++ if (ret) {
++ kfree(efi_name);
++ return ret;
++ }
++
++ ret = coreboot_cfr_read_efi_value_locked(efi_name, value, attrs);
++ efivar_unlock();
+ kfree(efi_name);
++
++ return ret;
++}
++
++static int coreboot_cfr_write_efi_value_locked(efi_char16_t *efi_name,
++ u32 value, u32 attrs)
++{
++ efi_status_t status;
++ __le32 data;
++
++ if (!efivar_supports_writes())
++ return -EROFS;
++
++ data = cpu_to_le32(value);
++ status = efivar_set_variable_locked(efi_name, &coreboot_cfr_guid, attrs,
++ sizeof(data), &data, false);
+ if (status != EFI_SUCCESS)
+ return efi_status_to_err(status);
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+#ifdef CONFIG_X86
+ u8 status;
+
-+ if (setting->runtime_apply_method != CFR_RUNTIME_APPLY_APM_CNT ||
-+ !setting->runtime_apply_id)
++ if (setting->runtime_apply_method != CFR_RUNTIME_APPLY_APM_CNT)
+ return -EOPNOTSUPP;
+
+ outb((u8)setting->runtime_apply_id, COREBOOT_CFR_APM_STS_PORT);
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+static int coreboot_cfr_write_value(struct coreboot_cfr_setting *setting,
+ u32 value)
+{
++ efi_char16_t *efi_name;
+ u32 attrs;
+ u32 old;
++ int restore_ret;
+ int ret;
+ bool changed = false;
+
+ if (setting->read_only)
+ return -EACCES;
+
-+ scoped_guard(mutex, &setting->drvdata->lock) {
-+ ret = coreboot_cfr_read_value(setting, &old, &attrs);
-+ if (ret)
-+ return ret;
++ efi_name = coreboot_cfr_efi_name(setting->name);
++ if (IS_ERR(efi_name))
++ return PTR_ERR(efi_name);
+
-+ if ((attrs & COREBOOT_CFR_EFI_ATTRS) != COREBOOT_CFR_EFI_ATTRS)
-+ return -EOPNOTSUPP;
++ mutex_lock(&setting->drvdata->lock);
++ ret = efivar_lock();
++ if (ret)
++ goto out_unlock_mutex;
++
++ ret = coreboot_cfr_read_efi_value_locked(efi_name, &old, &attrs);
++ if (ret)
++ goto out_unlock_efi;
+
-+ if (old == value)
-+ return 0;
++ if ((attrs & COREBOOT_CFR_EFI_ATTRS) != COREBOOT_CFR_EFI_ATTRS) {
++ ret = -EOPNOTSUPP;
++ goto out_unlock_efi;
++ }
+
-+ ret = coreboot_cfr_write_efi_value(setting, value, attrs);
-+ if (ret)
-+ return ret;
-+ changed = true;
++ if (old == value)
++ goto out_unlock_efi;
+
-+ ret = coreboot_cfr_apply_runtime(setting);
-+ if (ret == -EOPNOTSUPP) {
-+ /* EFI changed; firmware will consume it after reboot. */
++ ret = coreboot_cfr_write_efi_value_locked(efi_name, value, attrs);
++ if (ret)
++ goto out_unlock_efi;
++ changed = true;
++
++ ret = coreboot_cfr_apply_runtime(setting);
++ if (ret == -EOPNOTSUPP) {
++ /* EFI changed; firmware will consume it after reboot. */
++ setting->drvdata->pending_reboot = true;
++ ret = 0;
++ } else if (ret) {
++ restore_ret = coreboot_cfr_write_efi_value_locked(efi_name, old, attrs);
++ if (restore_ret) {
+ setting->drvdata->pending_reboot = true;
-+ ret = 0;
-+ } else if (ret) {
-+ int restore_ret;
-+
-+ restore_ret = coreboot_cfr_write_efi_value(setting, old, attrs);
-+ if (restore_ret)
-+ ret = restore_ret;
-+ else
-+ changed = false;
++ ret = restore_ret;
++ } else if (coreboot_cfr_apply_runtime(setting)) {
++ setting->drvdata->pending_reboot = true;
++ } else {
++ changed = false;
+ }
+ }
+
++out_unlock_efi:
++ efivar_unlock();
++out_unlock_mutex:
++ mutex_unlock(&setting->drvdata->lock);
++ kfree(efi_name);
++
+ if (changed)
+ kobject_uevent(&setting->drvdata->class_dev->kobj, KOBJ_CHANGE);
+ return ret;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+{
+ u32 delta;
+
-+ if (setting->type != COREBOOT_CFR_SETTING_NUMBER)
++ if (setting->type != COREBOOT_CFR_SETTING_NUMBER) {
++ /* Enum and bool values are valid only if they have a label. */
+ return coreboot_cfr_label_from_value(setting, value);
++ }
+
+ if (value < setting->min || value > setting->max)
+ return false;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ for (i = 0; i < setting->n_values; i++) {
+ len += sysfs_emit_at(buf, len, "%s%s", i ? ";" : "",
+ setting->values[i].label);
-+ if (len >= PAGE_SIZE)
-+ return len;
+ }
+
+ len += sysfs_emit_at(buf, len, "\n");
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+static int coreboot_cfr_count_enum_values(const void *base, size_t len)
+{
+ const struct coreboot_table_entry *entry;
-+ size_t off = 0;
++ size_t off;
+ int count = 0;
+
-+ while (off < len) {
++ for (off = 0; off < len; off += entry->size) {
+ if (len - off < sizeof(*entry))
+ return -EINVAL;
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+
+ if (entry->tag == CFR_TAG_ENUM_VALUE)
+ count++;
-+
-+ off += entry->size;
+ }
+
+ return count;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ const struct lb_cfr_enum_value *enum_value;
+ const struct lb_cfr_varbinary *label;
+ const struct coreboot_table_entry *entry;
-+ size_t off = 0;
++ size_t off;
+ int count;
+
+ count = coreboot_cfr_count_enum_values(base, len);
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ if (!setting->values)
+ return -ENOMEM;
+
-+ while (off < len) {
++ for (off = 0; off < len; off += entry->size) {
+ entry = base + off;
-+ if (entry->tag != CFR_TAG_ENUM_VALUE) {
-+ off += entry->size;
++ if (entry->tag != CFR_TAG_ENUM_VALUE)
+ continue;
-+ }
+
+ if (entry->size < sizeof(*enum_value))
+ return -EINVAL;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+
+ setting->values[setting->n_values].value = enum_value->value;
+ setting->n_values++;
-+ off += entry->size;
+ }
+
+ return 0;
+}
+
++static bool
++coreboot_cfr_possible_values_fit(const struct coreboot_cfr_setting *setting)
++{
++ size_t len = 1; /* Trailing newline. */
++ unsigned int i;
++
++ for (i = 0; i < setting->n_values; i++) {
++ if (i)
++ len++;
++
++ if (strlen(setting->values[i].label) >= PAGE_SIZE - len)
++ return false;
++
++ len += strlen(setting->values[i].label);
++ }
++
++ return true;
++}
++
+static int coreboot_cfr_setting_is_usable(struct coreboot_cfr_setting *setting)
+{
+ u32 value;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+}
+
+static int coreboot_cfr_add_numeric_option(struct coreboot_cfr_drvdata *data,
-+ const struct lb_cfr_numeric_option *option)
++ const struct lb_cfr_numeric_option *option,
++ bool parent_read_only)
+{
+ const struct lb_cfr_varbinary *name;
+ const struct lb_cfr_varbinary *display_name;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ setting->min = option->min;
+ setting->max = option->max;
+ setting->step = option->step ?: 1;
-+ setting->read_only = option->flags & COREBOOT_CFR_OPT_READ_ONLY_FLAGS;
++ setting->read_only =
++ (option->flags & COREBOOT_CFR_OPT_READ_ONLY_FLAGS) ||
++ !data->efi_writes_supported || parent_read_only;
+
+ runtime_apply = coreboot_cfr_child_runtime_apply(child_base, child_len);
+ if (IS_ERR(runtime_apply)) {
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ goto err_put_setting;
+ }
+
-+ if (runtime_apply && runtime_apply->method == CFR_RUNTIME_APPLY_APM_CNT &&
-+ runtime_apply->id) {
++ if (runtime_apply && runtime_apply->method == CFR_RUNTIME_APPLY_APM_CNT) {
+ setting->runtime_apply_method = runtime_apply->method;
+ setting->runtime_apply_id = runtime_apply->id;
+ }
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+
+ if (ret)
+ goto err_put_setting;
++ if (setting->type != COREBOOT_CFR_SETTING_NUMBER &&
++ !coreboot_cfr_possible_values_fit(setting)) {
++ ret = 0;
++ goto err_put_setting;
++ }
+
+ ret = coreboot_cfr_setting_is_usable(setting);
+ if (ret) {
-+ ret = 0;
++ if (ret == -ENOENT || ret == -EINVAL || ret == -EOPNOTSUPP ||
++ ret == -ENAMETOOLONG)
++ ret = 0;
+ goto err_put_setting;
+ }
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+}
+
+static int coreboot_cfr_parse_records(struct coreboot_cfr_drvdata *data,
-+ const void *base, size_t len)
++ const void *base, size_t len,
++ unsigned int depth,
++ bool parent_read_only)
+{
++ const struct lb_cfr_option_form *form;
+ const struct coreboot_table_entry *entry;
+ const void *child_base;
+ size_t child_len;
-+ size_t off = 0;
++ size_t off;
+ int ret;
+
-+ while (off < len) {
++ for (off = 0; off < len; off += entry->size) {
+ if (len - off < sizeof(*entry))
+ return -EINVAL;
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ if (entry->size < sizeof(struct lb_cfr_option_form))
+ return -EINVAL;
+
++ form = base + off;
++ if (form->dependency_id ||
++ form->flags & CFR_OPTFLAG_SUPPRESS)
++ break;
++
++ if (depth >= COREBOOT_CFR_MAX_FORM_DEPTH)
++ return -E2BIG;
++
+ child_base = base + off + sizeof(struct lb_cfr_option_form);
+ child_len = entry->size - sizeof(struct lb_cfr_option_form);
+ ret = coreboot_cfr_parse_records(data, child_base,
-+ child_len);
++ child_len, depth + 1,
++ parent_read_only ||
++ (form->flags &
++ COREBOOT_CFR_OPT_READ_ONLY_FLAGS));
+ if (ret)
+ return ret;
+ break;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ case CFR_TAG_OPTION_BOOL:
+ if (entry->size < sizeof(struct lb_cfr_numeric_option))
+ return -EINVAL;
-+ ret = coreboot_cfr_add_numeric_option(data, base + off);
++ ret = coreboot_cfr_add_numeric_option(data, base + off,
++ parent_read_only);
+ if (ret)
+ return ret;
+ break;
+ default:
++ /* Ignore unsupported, child-only and future record types. */
+ break;
+ }
-+
-+ off += entry->size;
+ }
+
+ return 0;
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ if (root->size < sizeof(*root) || root->size > dev->entry.size)
+ return -EINVAL;
+
++ payload_len = root->size - sizeof(*root);
++ if (crc32_be(0, root + 1, payload_len) != root->checksum)
++ return -EBADMSG;
++
+ if (!efivar_is_available())
+ return -EPROBE_DEFER;
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ if (!data)
+ return -ENOMEM;
+
++ ret = efivar_lock();
++ if (ret)
++ return ret;
++ data->efi_writes_supported = efivar_supports_writes();
++ efivar_unlock();
++
+ INIT_LIST_HEAD(&data->settings);
+ ret = devm_mutex_init(&dev->dev, &data->lock);
+ if (ret)
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+
+ data->class_dev = device_create(&firmware_attributes_class, NULL,
+ MKDEV(0, 0), NULL, DRIVER_NAME);
-+ if (IS_ERR(data->class_dev)) {
-+ ret = PTR_ERR(data->class_dev);
-+ goto err_clear_data;
-+ }
++ if (IS_ERR(data->class_dev))
++ return PTR_ERR(data->class_dev);
+ dev_set_drvdata(data->class_dev, data);
+
+ data->attrs_kset = kset_create_and_add("attributes", NULL,
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ if (ret)
+ goto err_unregister_attrs;
+
-+ payload_len = root->size - sizeof(*root);
-+ ret = coreboot_cfr_parse_records(data, root + 1, payload_len);
++ ret = coreboot_cfr_parse_records(data, root + 1, payload_len, 0, false);
+ if (ret)
+ goto err_unregister_settings;
+
@@ drivers/firmware/coreboot/coreboot-cfr.c (new)
+ kset_unregister(data->attrs_kset);
+err_unregister_dev:
+ device_unregister(data->class_dev);
-+err_clear_data:
+ return ret;
+}
+
--
2.53.0