From: Patrick Rudolph <patrick.rudo...@9elements.com> Expose the name of the active CBFS partition under /sys/firmware/cbfs_active_partition
In case of Google's VBOOT[1] that currently can be one of: "FW_MAIN_A", "FW_MAIN_B" or "COREBOOT" Will be used by fwupd[2] to determinde the active partition in the VBOOT A/B partition update scheme. [1]: https://doc.coreboot.org/security/vboot/index.html [2]: https://fwupd.org/ Signed-off-by: Patrick Rudolph <patrick.rudo...@9elements.com> --- drivers/firmware/google/Kconfig | 10 ++ drivers/firmware/google/Makefile | 1 + drivers/firmware/google/bootmedia-coreboot.c | 115 +++++++++++++++++++ drivers/firmware/google/coreboot_table.h | 13 +++ 4 files changed, 139 insertions(+) create mode 100644 drivers/firmware/google/bootmedia-coreboot.c diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig index 5fbbd7b8fef6..f58b723d77de 100644 --- a/drivers/firmware/google/Kconfig +++ b/drivers/firmware/google/Kconfig @@ -82,4 +82,14 @@ config GOOGLE_FMAP the coreboot table. If found, this binary file is exported to userland in the file /sys/firmware/fmap. +config GOOGLE_BOOTMEDIA + tristate "Coreboot bootmedia params access" + depends on GOOGLE_COREBOOT_TABLE + depends on GOOGLE_FMAP + help + This option enables the kernel to search for a boot media params + table, providing the active CBFS partition. If found, the name of + the partition is exported to userland in the file + /sys/firmware/cbfs_active_partition. + endif # GOOGLE_FIRMWARE diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile index 6d31fe167700..e47c59376566 100644 --- a/drivers/firmware/google/Makefile +++ b/drivers/firmware/google/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o obj-$(CONFIG_GOOGLE_FMAP) += fmap-coreboot.o +obj-$(CONFIG_GOOGLE_BOOTMEDIA) += bootmedia-coreboot.o vpd-sysfs-y := vpd.o vpd_decode.o obj-$(CONFIG_GOOGLE_VPD) += vpd-sysfs.o diff --git a/drivers/firmware/google/bootmedia-coreboot.c b/drivers/firmware/google/bootmedia-coreboot.c new file mode 100644 index 000000000000..09c0caedaf05 --- /dev/null +++ b/drivers/firmware/google/bootmedia-coreboot.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * bootmedia-coreboot.c + * + * Exports the active VBOOT partition name through boot media params. + * + * Copyright 2012-2013 David Herrmann <dh.herrm...@gmail.com> + * Copyright 2017 Google Inc. + * Copyright 2019 Patrick Rudolph <patrick.rudo...@9elements.com> + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/slab.h> + +#include "coreboot_table.h" +#include "fmap-coreboot.h" + +#define CB_TAG_BOOT_MEDIA_PARAMS 0x30 + +/* The current CBFS partition */ +static char *name; + +static ssize_t cbfs_active_partition_read(struct file *filp, + struct kobject *kobp, + struct bin_attribute *bin_attr, + char *buf, + loff_t pos, size_t count) +{ + if (!name) + return -ENODEV; + + return memory_read_from_buffer(buf, count, &pos, name, strlen(name)); +} + +static int bmp_probe(struct coreboot_device *dev) +{ + struct lb_boot_media_params *b = &dev->bmp; + const char *tmp; + + /* Sanity checks on the data we got */ + if ((b->cbfs_offset == ~0) || + b->cbfs_size == 0 || + ((b->cbfs_offset + b->cbfs_size) > b->boot_media_size)) { + pr_warn("coreboot: Boot media params contains invalid data\n"); + return -ENODEV; + } + + tmp = coreboot_fmap_region_to_name(b->cbfs_offset, b->cbfs_size); + if (!tmp) { + pr_warn("coreboot: Active CBFS region not found in FMAP\n"); + return -ENODEV; + } + + name = devm_kmalloc(&dev->dev, strlen(tmp) + 2, GFP_KERNEL); + if (!name) { + kfree(tmp); + return -ENODEV; + } + snprintf(name, strlen(tmp) + 2, "%s\n", tmp); + + kfree(tmp); + + return 0; +} + +static int bmp_remove(struct coreboot_device *dev) +{ + struct platform_device *pdev = dev_get_drvdata(&dev->dev); + + platform_device_unregister(pdev); + + return 0; +} + +static struct coreboot_driver bmp_driver = { + .probe = bmp_probe, + .remove = bmp_remove, + .drv = { + .name = "bootmediaparams", + }, + .tag = CB_TAG_BOOT_MEDIA_PARAMS, +}; + +static struct bin_attribute cbfs_partition_bin_attr = { + .attr = {.name = "cbfs_active_partition", .mode = 0444}, + .read = cbfs_active_partition_read, +}; + +static int __init coreboot_bmp_init(void) +{ + int err; + + err = sysfs_create_bin_file(firmware_kobj, &cbfs_partition_bin_attr); + if (err) + return err; + + return coreboot_driver_register(&bmp_driver); +} + +static void coreboot_bmp_exit(void) +{ + coreboot_driver_unregister(&bmp_driver); + sysfs_remove_bin_file(firmware_kobj, &cbfs_partition_bin_attr); +} + +module_init(coreboot_bmp_init); +module_exit(coreboot_bmp_exit); + +MODULE_AUTHOR("9elements Agency GmbH"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/google/coreboot_table.h b/drivers/firmware/google/coreboot_table.h index 7b7b4a6eedda..a03e039425b8 100644 --- a/drivers/firmware/google/coreboot_table.h +++ b/drivers/firmware/google/coreboot_table.h @@ -59,6 +59,18 @@ struct lb_framebuffer { u8 reserved_mask_size; }; +/* coreboot table with TAG 0x30 */ +struct lb_boot_media_params { + u32 tag; + u32 size; + + /* offsets are relative to start of boot media */ + u64 fmap_offset; + u64 cbfs_offset; + u64 cbfs_size; + u64 boot_media_size; +}; + /* A device, additionally with information from coreboot. */ struct coreboot_device { struct device dev; @@ -66,6 +78,7 @@ struct coreboot_device { struct coreboot_table_entry entry; struct lb_cbmem_ref cbmem_ref; struct lb_framebuffer framebuffer; + struct lb_boot_media_params bmp; }; }; -- 2.21.0