| 1 | |
| 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/device-id/coreboot.h>
|
| 16 | #include <linux/module.h>
|
| 17 | #include <linux/platform_device.h>
|
| 18 | #include <linux/slab.h>
|
| 19 | #include <linux/sysfs.h>
|
| 20 |
|
| 21 | #include "coreboot_table.h"
|
| 22 |
|
| 23 | struct cbmem_entry {
|
| 24 | char *mem_file_buf;
|
| 25 | u32 size;
|
| 26 | };
|
| 27 |
|
| 28 | static struct cbmem_entry *to_cbmem_entry(struct kobject *kobj)
|
| 29 | {
|
| 30 | return dev_get_drvdata(kobj_to_dev(kobj));
|
| 31 | }
|
| 32 |
|
| 33 | static ssize_t mem_read(struct file *filp, struct kobject *kobj,
|
| 34 | const struct bin_attribute *bin_attr, char *buf, loff_t pos,
|
| 35 | size_t count)
|
| 36 | {
|
| 37 | struct cbmem_entry *entry = to_cbmem_entry(kobj);
|
| 38 |
|
| 39 | return memory_read_from_buffer(buf, count, &pos, entry->mem_file_buf,
|
| 40 | entry->size);
|
| 41 | }
|
| 42 |
|
| 43 | static ssize_t mem_write(struct file *filp, struct kobject *kobj,
|
| 44 | const struct bin_attribute *bin_attr, char *buf, loff_t pos,
|
| 45 | size_t count)
|
| 46 | {
|
| 47 | struct cbmem_entry *entry = to_cbmem_entry(kobj);
|
| 48 |
|
| 49 | if (pos < 0 || pos >= entry->size)
|
| 50 | return -EINVAL;
|
| 51 | if (count > entry->size - pos)
|
| 52 | count = entry->size - pos;
|
| 53 |
|
| 54 | memcpy(entry->mem_file_buf + pos, buf, count);
|
| 55 | return count;
|
| 56 | }
|
| 57 | static const BIN_ATTR_ADMIN_RW(mem, 0);
|
| 58 |
|
| 59 | static ssize_t address_show(struct device *dev, struct device_attribute *attr,
|
| 60 | char *buf)
|
| 61 | {
|
| 62 | struct coreboot_device *cbdev = dev_to_coreboot_device(dev);
|
| 63 |
|
| 64 | return sysfs_emit(buf, "0x%llx\n", cbdev->cbmem_entry.address);
|
| 65 | }
|
| 66 | static DEVICE_ATTR_RO(address);
|
| 67 |
|
| 68 | static ssize_t size_show(struct device *dev, struct device_attribute *attr,
|
| 69 | char *buf)
|
| 70 | {
|
| 71 | struct coreboot_device *cbdev = dev_to_coreboot_device(dev);
|
| 72 |
|
| 73 | return sysfs_emit(buf, "0x%x\n", cbdev->cbmem_entry.entry_size);
|
| 74 | }
|
| 75 | static DEVICE_ATTR_RO(size);
|
| 76 |
|
| 77 | static struct attribute *attrs[] = {
|
| 78 | &dev_attr_address.attr,
|
| 79 | &dev_attr_size.attr,
|
| 80 | NULL,
|
| 81 | };
|
| 82 |
|
| 83 | static const struct bin_attribute *const bin_attrs[] = {
|
| 84 | &bin_attr_mem,
|
| 85 | NULL,
|
| 86 | };
|
| 87 |
|
| 88 | static const struct attribute_group cbmem_entry_group = {
|
| 89 | .attrs = attrs,
|
| 90 | .bin_attrs = bin_attrs,
|
| 91 | };
|
| 92 |
|
| 93 | static const struct attribute_group *dev_groups[] = {
|
| 94 | &cbmem_entry_group,
|
| 95 | NULL,
|
| 96 | };
|
| 97 |
|
| 98 | static int cbmem_entry_probe(struct coreboot_device *dev)
|
| 99 | {
|
| 100 | struct cbmem_entry *entry;
|
| 101 |
|
| 102 | entry = devm_kzalloc(&dev->dev, sizeof(*entry), GFP_KERNEL);
|
| 103 | if (!entry)
|
| 104 | return -ENOMEM;
|
| 105 |
|
| 106 | dev_set_drvdata(&dev->dev, entry);
|
| 107 | entry->mem_file_buf = devm_memremap(&dev->dev, dev->cbmem_entry.address,
|
| 108 | dev->cbmem_entry.entry_size,
|
| 109 | MEMREMAP_WB);
|
| 110 | if (IS_ERR(entry->mem_file_buf))
|
| 111 | return PTR_ERR(entry->mem_file_buf);
|
| 112 |
|
| 113 | entry->size = dev->cbmem_entry.entry_size;
|
| 114 |
|
| 115 | return 0;
|
| 116 | }
|
| 117 |
|
| 118 | static const struct coreboot_device_id cbmem_ids[] = {
|
| 119 | { .tag = LB_TAG_CBMEM_ENTRY },
|
| 120 | { }
|
| 121 | };
|
| 122 | MODULE_DEVICE_TABLE(coreboot, cbmem_ids);
|
| 123 |
|
| 124 | static struct coreboot_driver cbmem_entry_driver = {
|
| 125 | .probe = cbmem_entry_probe,
|
| 126 | .drv = {
|
| 127 | .name = "cbmem",
|
| 128 | .dev_groups = dev_groups,
|
| 129 | },
|
| 130 | .id_table = cbmem_ids,
|
| 131 | };
|
| 132 | module_coreboot_driver(cbmem_entry_driver);
|
| 133 |
|
| 134 | MODULE_AUTHOR("Jack Rosenthal <[email protected]>");
|
| 135 | MODULE_DESCRIPTION("Driver for exporting CBMEM entries in sysfs");
|
| 136 | MODULE_LICENSE("GPL");
|