Skip to content

Commit 19d5402

Browse files
jackrosenthalgregkh
authored andcommitted
firmware: google: Implement cbmem in sysfs driver
The CBMEM area is a downward-growing memory region used by coreboot to dynamically allocate tagged data structures ("CBMEM entries") that remain resident during boot. This implements a driver which exports access to the CBMEM entries via sysfs under /sys/bus/coreboot/devices/cbmem-<id>. This implementation is quite versatile. Examples of how it could be used are given below: * Tools like util/cbmem from the coreboot tree could use this driver instead of finding CBMEM in /dev/mem directly. Alternatively, firmware developers debugging an issue may find the sysfs interface more ergonomic than the cbmem tool and choose to use it directly. * The crossystem tool, which exposes verified boot variables, can use this driver to read the vboot work buffer. * Tools which read the BIOS SPI flash (e.g., flashrom) can find the flash layout in CBMEM directly, which is significantly faster than searching the flash directly. Write access is provided to all CBMEM regions via /sys/bus/coreboot/devices/cbmem-<id>/mem, as the existing cbmem tooling updates this memory region, and envisioned use cases with crossystem can benefit from updating memory regions. Link: https://issuetracker.google.com/239604743 Cc: Stephen Boyd <swboyd@chromium.org> Cc: Tzung-Bi Shih <tzungbi@kernel.org> Reviewed-by: Guenter Roeck <groeck@chromium.org> Reviewed-by: Julius Werner <jwerner@chromium.org> Tested-by: Jack Rosenthal <jrosenth@chromium.org> Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Link: https://lore.kernel.org/r/20221104161528.531248-1-jrosenth@chromium.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d88bd09 commit 19d5402

File tree

6 files changed

+220
-1
lines changed

6 files changed

+220
-1
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
What: /sys/bus/coreboot
2+
Date: August 2022
3+
Contact: Jack Rosenthal <jrosenth@chromium.org>
4+
Description:
5+
The coreboot bus provides a variety of virtual devices used to
6+
access data structures created by the Coreboot BIOS.
7+
8+
What: /sys/bus/coreboot/devices/cbmem-<id>
9+
Date: August 2022
10+
Contact: Jack Rosenthal <jrosenth@chromium.org>
11+
Description:
12+
CBMEM is a downwards-growing memory region created by Coreboot,
13+
and contains tagged data structures to be shared with payloads
14+
in the boot process and the OS. Each CBMEM entry is given a
15+
directory in /sys/bus/coreboot/devices based on its id.
16+
A list of ids known to Coreboot can be found in the coreboot
17+
source tree at
18+
``src/commonlib/bsd/include/commonlib/bsd/cbmem_id.h``.
19+
20+
What: /sys/bus/coreboot/devices/cbmem-<id>/address
21+
Date: August 2022
22+
Contact: Jack Rosenthal <jrosenth@chromium.org>
23+
Description:
24+
This is the pyhsical memory address that the CBMEM entry's data
25+
begins at, in hexadecimal (e.g., ``0x76ffe000``).
26+
27+
What: /sys/bus/coreboot/devices/cbmem-<id>/size
28+
Date: August 2022
29+
Contact: Jack Rosenthal <jrosenth@chromium.org>
30+
Description:
31+
This is the size of the CBMEM entry's data, in hexadecimal
32+
(e.g., ``0x1234``).
33+
34+
What: /sys/bus/coreboot/devices/cbmem-<id>/mem
35+
Date: August 2022
36+
Contact: Jack Rosenthal <jrosenth@chromium.org>
37+
Description:
38+
A file exposing read/write access to the entry's data. Note
39+
that this file does not support mmap(), as coreboot
40+
does not guarantee that the data will be page-aligned.
41+
42+
The mode of this file is 0600. While there shouldn't be
43+
anything security-sensitive contained in CBMEM, read access
44+
requires root privileges given this is exposing a small subset
45+
of physical memory.

drivers/firmware/google/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ config GOOGLE_SMI
1919
driver provides an interface for reading and writing NVRAM
2020
variables.
2121

22+
config GOOGLE_CBMEM
23+
tristate "CBMEM entries in sysfs"
24+
depends on GOOGLE_COREBOOT_TABLE
25+
help
26+
CBMEM is a downwards-growing memory region created by the
27+
Coreboot BIOS containing tagged data structures from the
28+
BIOS. These data structures expose things like the verified
29+
boot firmware variables, flash layout, firmware event log,
30+
and more.
31+
32+
This option enables the cbmem module, which causes the
33+
kernel to search for Coreboot CBMEM entries, and expose the
34+
memory for each entry in sysfs under
35+
/sys/bus/coreboot/devices/cbmem-<id>.
36+
2237
config GOOGLE_COREBOOT_TABLE
2338
tristate "Coreboot Table Access"
2439
depends on HAS_IOMEM && (ACPI || OF)

drivers/firmware/google/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o
77
obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o
88
obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o
99

10+
# Must come after coreboot_table.o, as this driver depends on that bus type.
11+
obj-$(CONFIG_GOOGLE_CBMEM) += cbmem.o
12+
1013
vpd-sysfs-y := vpd.o vpd_decode.o
1114
obj-$(CONFIG_GOOGLE_VPD) += vpd-sysfs.o

drivers/firmware/google/cbmem.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* cbmem.c
4+
*
5+
* Driver for exporting cbmem entries in sysfs.
6+
*
7+
* Copyright 2022 Google LLC
8+
*/
9+
10+
#include <linux/device.h>
11+
#include <linux/init.h>
12+
#include <linux/io.h>
13+
#include <linux/kernel.h>
14+
#include <linux/kobject.h>
15+
#include <linux/module.h>
16+
#include <linux/platform_device.h>
17+
#include <linux/slab.h>
18+
#include <linux/sysfs.h>
19+
20+
#include "coreboot_table.h"
21+
22+
struct cbmem_entry {
23+
char *mem_file_buf;
24+
u32 size;
25+
};
26+
27+
static struct cbmem_entry *to_cbmem_entry(struct kobject *kobj)
28+
{
29+
return dev_get_drvdata(kobj_to_dev(kobj));
30+
}
31+
32+
static ssize_t mem_read(struct file *filp, struct kobject *kobj,
33+
struct bin_attribute *bin_attr, char *buf, loff_t pos,
34+
size_t count)
35+
{
36+
struct cbmem_entry *entry = to_cbmem_entry(kobj);
37+
38+
return memory_read_from_buffer(buf, count, &pos, entry->mem_file_buf,
39+
entry->size);
40+
}
41+
42+
static ssize_t mem_write(struct file *filp, struct kobject *kobj,
43+
struct bin_attribute *bin_attr, char *buf, loff_t pos,
44+
size_t count)
45+
{
46+
struct cbmem_entry *entry = to_cbmem_entry(kobj);
47+
48+
if (pos < 0 || pos >= entry->size)
49+
return -EINVAL;
50+
if (count > entry->size - pos)
51+
count = entry->size - pos;
52+
53+
memcpy(entry->mem_file_buf + pos, buf, count);
54+
return count;
55+
}
56+
static BIN_ATTR_ADMIN_RW(mem, 0);
57+
58+
static ssize_t address_show(struct device *dev, struct device_attribute *attr,
59+
char *buf)
60+
{
61+
struct coreboot_device *cbdev = dev_to_coreboot_device(dev);
62+
63+
return sysfs_emit(buf, "0x%llx\n", cbdev->cbmem_entry.address);
64+
}
65+
static DEVICE_ATTR_RO(address);
66+
67+
static ssize_t size_show(struct device *dev, struct device_attribute *attr,
68+
char *buf)
69+
{
70+
struct coreboot_device *cbdev = dev_to_coreboot_device(dev);
71+
72+
return sysfs_emit(buf, "0x%x\n", cbdev->cbmem_entry.entry_size);
73+
}
74+
static DEVICE_ATTR_RO(size);
75+
76+
static struct attribute *attrs[] = {
77+
&dev_attr_address.attr,
78+
&dev_attr_size.attr,
79+
NULL,
80+
};
81+
82+
static struct bin_attribute *bin_attrs[] = {
83+
&bin_attr_mem,
84+
NULL,
85+
};
86+
87+
static const struct attribute_group cbmem_entry_group = {
88+
.attrs = attrs,
89+
.bin_attrs = bin_attrs,
90+
};
91+
92+
static const struct attribute_group *dev_groups[] = {
93+
&cbmem_entry_group,
94+
NULL,
95+
};
96+
97+
static int cbmem_entry_probe(struct coreboot_device *dev)
98+
{
99+
struct cbmem_entry *entry;
100+
101+
entry = devm_kzalloc(&dev->dev, sizeof(*entry), GFP_KERNEL);
102+
if (!entry)
103+
return -ENOMEM;
104+
105+
dev_set_drvdata(&dev->dev, entry);
106+
entry->mem_file_buf = devm_memremap(&dev->dev, dev->cbmem_entry.address,
107+
dev->cbmem_entry.entry_size,
108+
MEMREMAP_WB);
109+
if (!entry->mem_file_buf)
110+
return -ENOMEM;
111+
112+
entry->size = dev->cbmem_entry.entry_size;
113+
114+
return 0;
115+
}
116+
117+
static struct coreboot_driver cbmem_entry_driver = {
118+
.probe = cbmem_entry_probe,
119+
.drv = {
120+
.name = "cbmem",
121+
.owner = THIS_MODULE,
122+
.dev_groups = dev_groups,
123+
},
124+
.tag = LB_TAG_CBMEM_ENTRY,
125+
};
126+
module_coreboot_driver(cbmem_entry_driver);
127+
128+
MODULE_AUTHOR("Jack Rosenthal <jrosenth@chromium.org>");
129+
MODULE_LICENSE("GPL");

drivers/firmware/google/coreboot_table.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,21 @@ static int coreboot_table_populate(struct device *dev, void *ptr)
9797
if (!device)
9898
return -ENOMEM;
9999

100-
dev_set_name(&device->dev, "coreboot%d", i);
101100
device->dev.parent = dev;
102101
device->dev.bus = &coreboot_bus_type;
103102
device->dev.release = coreboot_device_release;
104103
memcpy(&device->entry, ptr_entry, entry->size);
105104

105+
switch (device->entry.tag) {
106+
case LB_TAG_CBMEM_ENTRY:
107+
dev_set_name(&device->dev, "cbmem-%08x",
108+
device->cbmem_entry.id);
109+
break;
110+
default:
111+
dev_set_name(&device->dev, "coreboot%d", i);
112+
break;
113+
}
114+
106115
ret = device_register(&device->dev);
107116
if (ret) {
108117
put_device(&device->dev);

drivers/firmware/google/coreboot_table.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ struct lb_cbmem_ref {
3939
u64 cbmem_addr;
4040
};
4141

42+
#define LB_TAG_CBMEM_ENTRY 0x31
43+
44+
/* Corresponds to LB_TAG_CBMEM_ENTRY */
45+
struct lb_cbmem_entry {
46+
u32 tag;
47+
u32 size;
48+
49+
u64 address;
50+
u32 entry_size;
51+
u32 id;
52+
};
53+
4254
/* Describes framebuffer setup by coreboot */
4355
struct lb_framebuffer {
4456
u32 tag;
@@ -65,10 +77,16 @@ struct coreboot_device {
6577
union {
6678
struct coreboot_table_entry entry;
6779
struct lb_cbmem_ref cbmem_ref;
80+
struct lb_cbmem_entry cbmem_entry;
6881
struct lb_framebuffer framebuffer;
6982
};
7083
};
7184

85+
static inline struct coreboot_device *dev_to_coreboot_device(struct device *dev)
86+
{
87+
return container_of(dev, struct coreboot_device, dev);
88+
}
89+
7290
/* A driver for handling devices described in coreboot tables. */
7391
struct coreboot_driver {
7492
int (*probe)(struct coreboot_device *);

0 commit comments

Comments
 (0)