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");