1 // SPDX-License-Identifier: GPL-2.0-only
5 * Driver for exporting VPD content to sysfs.
7 * Copyright 2017 Google Inc.
10 #include <linux/ctype.h>
11 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/kobject.h>
15 #include <linux/list.h>
16 #include <linux/module.h>
17 #include <linux/of_address.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20 #include <linux/sysfs.h>
22 #include "coreboot_table.h"
23 #include "vpd_decode.h"
25 #define CB_TAG_VPD 0x2c
26 #define VPD_CBMEM_MAGIC 0x43524f53
28 static struct kobject *vpd_kobj;
41 char *raw_name; /* the string name_raw */
42 struct kobject *kobj; /* vpd/name directory */
44 struct bin_attribute bin_attr; /* vpd/name_raw bin_attribute */
45 struct list_head attribs; /* key/value in vpd_attrib_info list */
48 struct vpd_attrib_info {
51 struct bin_attribute bin_attr;
52 struct list_head list;
55 static struct vpd_section ro_vpd;
56 static struct vpd_section rw_vpd;
58 static ssize_t vpd_attrib_read(struct file *filp, struct kobject *kobp,
59 struct bin_attribute *bin_attr, char *buf,
60 loff_t pos, size_t count)
62 struct vpd_attrib_info *info = bin_attr->private;
64 return memory_read_from_buffer(buf, count, &pos, info->value,
69 * vpd_section_check_key_name()
71 * The VPD specification supports only [a-zA-Z0-9_]+ characters in key names but
72 * old firmware versions may have entries like "S/N" which are problematic when
73 * exporting them as sysfs attributes. These keys present in old firmwares are
76 * Returns VPD_OK for a valid key name, VPD_FAIL otherwise.
78 * @key: The key name to check
79 * @key_len: key name length
81 static int vpd_section_check_key_name(const u8 *key, s32 key_len)
85 while (key_len-- > 0) {
88 if (!isalnum(c) && c != '_')
95 static int vpd_section_attrib_add(const u8 *key, u32 key_len,
96 const u8 *value, u32 value_len,
100 struct vpd_section *sec = arg;
101 struct vpd_attrib_info *info;
104 * Return VPD_OK immediately to decode next entry if the current key
105 * name contains invalid characters.
107 if (vpd_section_check_key_name(key, key_len) != VPD_OK)
110 info = kzalloc(sizeof(*info), GFP_KERNEL);
114 info->key = kstrndup(key, key_len, GFP_KERNEL);
120 sysfs_bin_attr_init(&info->bin_attr);
121 info->bin_attr.attr.name = info->key;
122 info->bin_attr.attr.mode = 0444;
123 info->bin_attr.size = value_len;
124 info->bin_attr.read = vpd_attrib_read;
125 info->bin_attr.private = info;
129 INIT_LIST_HEAD(&info->list);
131 ret = sysfs_create_bin_file(sec->kobj, &info->bin_attr);
135 list_add_tail(&info->list, &sec->attribs);
146 static void vpd_section_attrib_destroy(struct vpd_section *sec)
148 struct vpd_attrib_info *info;
149 struct vpd_attrib_info *temp;
151 list_for_each_entry_safe(info, temp, &sec->attribs, list) {
152 sysfs_remove_bin_file(sec->kobj, &info->bin_attr);
158 static ssize_t vpd_section_read(struct file *filp, struct kobject *kobp,
159 struct bin_attribute *bin_attr, char *buf,
160 loff_t pos, size_t count)
162 struct vpd_section *sec = bin_attr->private;
164 return memory_read_from_buffer(buf, count, &pos, sec->baseaddr,
168 static int vpd_section_create_attribs(struct vpd_section *sec)
175 ret = vpd_decode_string(sec->bin_attr.size, sec->baseaddr,
176 &consumed, vpd_section_attrib_add, sec);
177 } while (ret == VPD_OK);
182 static int vpd_section_init(const char *name, struct vpd_section *sec,
183 phys_addr_t physaddr, size_t size)
187 sec->baseaddr = memremap(physaddr, size, MEMREMAP_WB);
193 /* We want to export the raw partition with name ${name}_raw */
194 sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name);
195 if (!sec->raw_name) {
200 sysfs_bin_attr_init(&sec->bin_attr);
201 sec->bin_attr.attr.name = sec->raw_name;
202 sec->bin_attr.attr.mode = 0444;
203 sec->bin_attr.size = size;
204 sec->bin_attr.read = vpd_section_read;
205 sec->bin_attr.private = sec;
207 err = sysfs_create_bin_file(vpd_kobj, &sec->bin_attr);
209 goto err_free_raw_name;
211 sec->kobj = kobject_create_and_add(name, vpd_kobj);
214 goto err_sysfs_remove;
217 INIT_LIST_HEAD(&sec->attribs);
218 vpd_section_create_attribs(sec);
225 sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr);
227 kfree(sec->raw_name);
229 memunmap(sec->baseaddr);
233 static int vpd_section_destroy(struct vpd_section *sec)
236 vpd_section_attrib_destroy(sec);
237 kobject_put(sec->kobj);
238 sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr);
239 kfree(sec->raw_name);
240 memunmap(sec->baseaddr);
241 sec->enabled = false;
247 static int vpd_sections_init(phys_addr_t physaddr)
249 struct vpd_cbmem *temp;
250 struct vpd_cbmem header;
253 temp = memremap(physaddr, sizeof(struct vpd_cbmem), MEMREMAP_WB);
257 memcpy(&header, temp, sizeof(struct vpd_cbmem));
260 if (header.magic != VPD_CBMEM_MAGIC)
263 if (header.ro_size) {
264 ret = vpd_section_init("ro", &ro_vpd,
265 physaddr + sizeof(struct vpd_cbmem),
271 if (header.rw_size) {
272 ret = vpd_section_init("rw", &rw_vpd,
273 physaddr + sizeof(struct vpd_cbmem) +
274 header.ro_size, header.rw_size);
276 vpd_section_destroy(&ro_vpd);
284 static int vpd_probe(struct coreboot_device *dev)
288 vpd_kobj = kobject_create_and_add("vpd", firmware_kobj);
292 ret = vpd_sections_init(dev->cbmem_ref.cbmem_addr);
294 kobject_put(vpd_kobj);
301 static int vpd_remove(struct coreboot_device *dev)
303 vpd_section_destroy(&ro_vpd);
304 vpd_section_destroy(&rw_vpd);
306 kobject_put(vpd_kobj);
311 static struct coreboot_driver vpd_driver = {
313 .remove = vpd_remove,
319 module_coreboot_driver(vpd_driver);
321 MODULE_AUTHOR("Google, Inc.");
322 MODULE_LICENSE("GPL");