xref: /linux/drivers/firmware/coreboot/vpd.c (revision 9e947d96915af63e28896caae85a81b74855621b)
1*44e33a5aSSean Rhodes // SPDX-License-Identifier: GPL-2.0-only
2*44e33a5aSSean Rhodes /*
3*44e33a5aSSean Rhodes  * vpd.c
4*44e33a5aSSean Rhodes  *
5*44e33a5aSSean Rhodes  * Driver for exporting VPD content to sysfs.
6*44e33a5aSSean Rhodes  *
7*44e33a5aSSean Rhodes  * Copyright 2017 Google Inc.
8*44e33a5aSSean Rhodes  */
9*44e33a5aSSean Rhodes 
10*44e33a5aSSean Rhodes #include <linux/ctype.h>
11*44e33a5aSSean Rhodes #include <linux/init.h>
12*44e33a5aSSean Rhodes #include <linux/io.h>
13*44e33a5aSSean Rhodes #include <linux/kernel.h>
14*44e33a5aSSean Rhodes #include <linux/kobject.h>
15*44e33a5aSSean Rhodes #include <linux/list.h>
16*44e33a5aSSean Rhodes #include <linux/device-id/coreboot.h>
17*44e33a5aSSean Rhodes #include <linux/module.h>
18*44e33a5aSSean Rhodes #include <linux/of_address.h>
19*44e33a5aSSean Rhodes #include <linux/platform_device.h>
20*44e33a5aSSean Rhodes #include <linux/slab.h>
21*44e33a5aSSean Rhodes #include <linux/sysfs.h>
22*44e33a5aSSean Rhodes 
23*44e33a5aSSean Rhodes #include "coreboot_table.h"
24*44e33a5aSSean Rhodes #include "vpd_decode.h"
25*44e33a5aSSean Rhodes 
26*44e33a5aSSean Rhodes #define CB_TAG_VPD      0x2c
27*44e33a5aSSean Rhodes #define VPD_CBMEM_MAGIC 0x43524f53
28*44e33a5aSSean Rhodes 
29*44e33a5aSSean Rhodes static struct kobject *vpd_kobj;
30*44e33a5aSSean Rhodes 
31*44e33a5aSSean Rhodes struct vpd_cbmem {
32*44e33a5aSSean Rhodes 	u32 magic;
33*44e33a5aSSean Rhodes 	u32 version;
34*44e33a5aSSean Rhodes 	u32 ro_size;
35*44e33a5aSSean Rhodes 	u32 rw_size;
36*44e33a5aSSean Rhodes 	u8  blob[];
37*44e33a5aSSean Rhodes };
38*44e33a5aSSean Rhodes 
39*44e33a5aSSean Rhodes struct vpd_section {
40*44e33a5aSSean Rhodes 	bool enabled;
41*44e33a5aSSean Rhodes 	const char *name;
42*44e33a5aSSean Rhodes 	char *raw_name;                /* the string name_raw */
43*44e33a5aSSean Rhodes 	struct kobject *kobj;          /* vpd/name directory */
44*44e33a5aSSean Rhodes 	char *baseaddr;
45*44e33a5aSSean Rhodes 	struct bin_attribute bin_attr; /* vpd/name_raw bin_attribute */
46*44e33a5aSSean Rhodes 	struct list_head attribs;      /* key/value in vpd_attrib_info list */
47*44e33a5aSSean Rhodes };
48*44e33a5aSSean Rhodes 
49*44e33a5aSSean Rhodes struct vpd_attrib_info {
50*44e33a5aSSean Rhodes 	char *key;
51*44e33a5aSSean Rhodes 	const char *value;
52*44e33a5aSSean Rhodes 	struct bin_attribute bin_attr;
53*44e33a5aSSean Rhodes 	struct list_head list;
54*44e33a5aSSean Rhodes };
55*44e33a5aSSean Rhodes 
56*44e33a5aSSean Rhodes static struct vpd_section ro_vpd;
57*44e33a5aSSean Rhodes static struct vpd_section rw_vpd;
58*44e33a5aSSean Rhodes 
vpd_attrib_read(struct file * filp,struct kobject * kobp,const struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)59*44e33a5aSSean Rhodes static ssize_t vpd_attrib_read(struct file *filp, struct kobject *kobp,
60*44e33a5aSSean Rhodes 			       const struct bin_attribute *bin_attr, char *buf,
61*44e33a5aSSean Rhodes 			       loff_t pos, size_t count)
62*44e33a5aSSean Rhodes {
63*44e33a5aSSean Rhodes 	struct vpd_attrib_info *info = bin_attr->private;
64*44e33a5aSSean Rhodes 
65*44e33a5aSSean Rhodes 	return memory_read_from_buffer(buf, count, &pos, info->value,
66*44e33a5aSSean Rhodes 				       info->bin_attr.size);
67*44e33a5aSSean Rhodes }
68*44e33a5aSSean Rhodes 
69*44e33a5aSSean Rhodes /*
70*44e33a5aSSean Rhodes  * vpd_section_check_key_name()
71*44e33a5aSSean Rhodes  *
72*44e33a5aSSean Rhodes  * The VPD specification supports only [a-zA-Z0-9_]+ characters in key names but
73*44e33a5aSSean Rhodes  * old firmware versions may have entries like "S/N" which are problematic when
74*44e33a5aSSean Rhodes  * exporting them as sysfs attributes. These keys present in old firmwares are
75*44e33a5aSSean Rhodes  * ignored.
76*44e33a5aSSean Rhodes  *
77*44e33a5aSSean Rhodes  * Returns VPD_OK for a valid key name, VPD_FAIL otherwise.
78*44e33a5aSSean Rhodes  *
79*44e33a5aSSean Rhodes  * @key: The key name to check
80*44e33a5aSSean Rhodes  * @key_len: key name length
81*44e33a5aSSean Rhodes  */
vpd_section_check_key_name(const u8 * key,s32 key_len)82*44e33a5aSSean Rhodes static int vpd_section_check_key_name(const u8 *key, s32 key_len)
83*44e33a5aSSean Rhodes {
84*44e33a5aSSean Rhodes 	int c;
85*44e33a5aSSean Rhodes 
86*44e33a5aSSean Rhodes 	while (key_len-- > 0) {
87*44e33a5aSSean Rhodes 		c = *key++;
88*44e33a5aSSean Rhodes 
89*44e33a5aSSean Rhodes 		if (!isalnum(c) && c != '_')
90*44e33a5aSSean Rhodes 			return VPD_FAIL;
91*44e33a5aSSean Rhodes 	}
92*44e33a5aSSean Rhodes 
93*44e33a5aSSean Rhodes 	return VPD_OK;
94*44e33a5aSSean Rhodes }
95*44e33a5aSSean Rhodes 
vpd_section_attrib_add(const u8 * key,u32 key_len,const u8 * value,u32 value_len,void * arg)96*44e33a5aSSean Rhodes static int vpd_section_attrib_add(const u8 *key, u32 key_len,
97*44e33a5aSSean Rhodes 				  const u8 *value, u32 value_len,
98*44e33a5aSSean Rhodes 				  void *arg)
99*44e33a5aSSean Rhodes {
100*44e33a5aSSean Rhodes 	int ret;
101*44e33a5aSSean Rhodes 	struct vpd_section *sec = arg;
102*44e33a5aSSean Rhodes 	struct vpd_attrib_info *info;
103*44e33a5aSSean Rhodes 
104*44e33a5aSSean Rhodes 	/*
105*44e33a5aSSean Rhodes 	 * Return VPD_OK immediately to decode next entry if the current key
106*44e33a5aSSean Rhodes 	 * name contains invalid characters.
107*44e33a5aSSean Rhodes 	 */
108*44e33a5aSSean Rhodes 	if (vpd_section_check_key_name(key, key_len) != VPD_OK)
109*44e33a5aSSean Rhodes 		return VPD_OK;
110*44e33a5aSSean Rhodes 
111*44e33a5aSSean Rhodes 	info = kzalloc_obj(*info);
112*44e33a5aSSean Rhodes 	if (!info)
113*44e33a5aSSean Rhodes 		return -ENOMEM;
114*44e33a5aSSean Rhodes 
115*44e33a5aSSean Rhodes 	info->key = kstrndup(key, key_len, GFP_KERNEL);
116*44e33a5aSSean Rhodes 	if (!info->key) {
117*44e33a5aSSean Rhodes 		ret = -ENOMEM;
118*44e33a5aSSean Rhodes 		goto free_info;
119*44e33a5aSSean Rhodes 	}
120*44e33a5aSSean Rhodes 
121*44e33a5aSSean Rhodes 	sysfs_bin_attr_init(&info->bin_attr);
122*44e33a5aSSean Rhodes 	info->bin_attr.attr.name = info->key;
123*44e33a5aSSean Rhodes 	info->bin_attr.attr.mode = 0444;
124*44e33a5aSSean Rhodes 	info->bin_attr.size = value_len;
125*44e33a5aSSean Rhodes 	info->bin_attr.read = vpd_attrib_read;
126*44e33a5aSSean Rhodes 	info->bin_attr.private = info;
127*44e33a5aSSean Rhodes 
128*44e33a5aSSean Rhodes 	info->value = value;
129*44e33a5aSSean Rhodes 
130*44e33a5aSSean Rhodes 	INIT_LIST_HEAD(&info->list);
131*44e33a5aSSean Rhodes 
132*44e33a5aSSean Rhodes 	ret = sysfs_create_bin_file(sec->kobj, &info->bin_attr);
133*44e33a5aSSean Rhodes 	if (ret)
134*44e33a5aSSean Rhodes 		goto free_info_key;
135*44e33a5aSSean Rhodes 
136*44e33a5aSSean Rhodes 	list_add_tail(&info->list, &sec->attribs);
137*44e33a5aSSean Rhodes 	return 0;
138*44e33a5aSSean Rhodes 
139*44e33a5aSSean Rhodes free_info_key:
140*44e33a5aSSean Rhodes 	kfree(info->key);
141*44e33a5aSSean Rhodes free_info:
142*44e33a5aSSean Rhodes 	kfree(info);
143*44e33a5aSSean Rhodes 
144*44e33a5aSSean Rhodes 	return ret;
145*44e33a5aSSean Rhodes }
146*44e33a5aSSean Rhodes 
vpd_section_attrib_destroy(struct vpd_section * sec)147*44e33a5aSSean Rhodes static void vpd_section_attrib_destroy(struct vpd_section *sec)
148*44e33a5aSSean Rhodes {
149*44e33a5aSSean Rhodes 	struct vpd_attrib_info *info;
150*44e33a5aSSean Rhodes 	struct vpd_attrib_info *temp;
151*44e33a5aSSean Rhodes 
152*44e33a5aSSean Rhodes 	list_for_each_entry_safe(info, temp, &sec->attribs, list) {
153*44e33a5aSSean Rhodes 		sysfs_remove_bin_file(sec->kobj, &info->bin_attr);
154*44e33a5aSSean Rhodes 		kfree(info->key);
155*44e33a5aSSean Rhodes 		kfree(info);
156*44e33a5aSSean Rhodes 	}
157*44e33a5aSSean Rhodes }
158*44e33a5aSSean Rhodes 
vpd_section_read(struct file * filp,struct kobject * kobp,const struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)159*44e33a5aSSean Rhodes static ssize_t vpd_section_read(struct file *filp, struct kobject *kobp,
160*44e33a5aSSean Rhodes 				const struct bin_attribute *bin_attr, char *buf,
161*44e33a5aSSean Rhodes 				loff_t pos, size_t count)
162*44e33a5aSSean Rhodes {
163*44e33a5aSSean Rhodes 	struct vpd_section *sec = bin_attr->private;
164*44e33a5aSSean Rhodes 
165*44e33a5aSSean Rhodes 	return memory_read_from_buffer(buf, count, &pos, sec->baseaddr,
166*44e33a5aSSean Rhodes 				       sec->bin_attr.size);
167*44e33a5aSSean Rhodes }
168*44e33a5aSSean Rhodes 
vpd_section_create_attribs(struct vpd_section * sec)169*44e33a5aSSean Rhodes static int vpd_section_create_attribs(struct vpd_section *sec)
170*44e33a5aSSean Rhodes {
171*44e33a5aSSean Rhodes 	s32 consumed;
172*44e33a5aSSean Rhodes 	int ret;
173*44e33a5aSSean Rhodes 
174*44e33a5aSSean Rhodes 	consumed = 0;
175*44e33a5aSSean Rhodes 	do {
176*44e33a5aSSean Rhodes 		ret = vpd_decode_string(sec->bin_attr.size, sec->baseaddr,
177*44e33a5aSSean Rhodes 					&consumed, vpd_section_attrib_add, sec);
178*44e33a5aSSean Rhodes 	} while (ret == VPD_OK);
179*44e33a5aSSean Rhodes 
180*44e33a5aSSean Rhodes 	return 0;
181*44e33a5aSSean Rhodes }
182*44e33a5aSSean Rhodes 
vpd_section_init(const char * name,struct vpd_section * sec,phys_addr_t physaddr,size_t size)183*44e33a5aSSean Rhodes static int vpd_section_init(const char *name, struct vpd_section *sec,
184*44e33a5aSSean Rhodes 			    phys_addr_t physaddr, size_t size)
185*44e33a5aSSean Rhodes {
186*44e33a5aSSean Rhodes 	int err;
187*44e33a5aSSean Rhodes 
188*44e33a5aSSean Rhodes 	sec->baseaddr = memremap(physaddr, size, MEMREMAP_WB);
189*44e33a5aSSean Rhodes 	if (!sec->baseaddr)
190*44e33a5aSSean Rhodes 		return -ENOMEM;
191*44e33a5aSSean Rhodes 
192*44e33a5aSSean Rhodes 	sec->name = name;
193*44e33a5aSSean Rhodes 
194*44e33a5aSSean Rhodes 	/* We want to export the raw partition with name ${name}_raw */
195*44e33a5aSSean Rhodes 	sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name);
196*44e33a5aSSean Rhodes 	if (!sec->raw_name) {
197*44e33a5aSSean Rhodes 		err = -ENOMEM;
198*44e33a5aSSean Rhodes 		goto err_memunmap;
199*44e33a5aSSean Rhodes 	}
200*44e33a5aSSean Rhodes 
201*44e33a5aSSean Rhodes 	sysfs_bin_attr_init(&sec->bin_attr);
202*44e33a5aSSean Rhodes 	sec->bin_attr.attr.name = sec->raw_name;
203*44e33a5aSSean Rhodes 	sec->bin_attr.attr.mode = 0444;
204*44e33a5aSSean Rhodes 	sec->bin_attr.size = size;
205*44e33a5aSSean Rhodes 	sec->bin_attr.read = vpd_section_read;
206*44e33a5aSSean Rhodes 	sec->bin_attr.private = sec;
207*44e33a5aSSean Rhodes 
208*44e33a5aSSean Rhodes 	err = sysfs_create_bin_file(vpd_kobj, &sec->bin_attr);
209*44e33a5aSSean Rhodes 	if (err)
210*44e33a5aSSean Rhodes 		goto err_free_raw_name;
211*44e33a5aSSean Rhodes 
212*44e33a5aSSean Rhodes 	sec->kobj = kobject_create_and_add(name, vpd_kobj);
213*44e33a5aSSean Rhodes 	if (!sec->kobj) {
214*44e33a5aSSean Rhodes 		err = -EINVAL;
215*44e33a5aSSean Rhodes 		goto err_sysfs_remove;
216*44e33a5aSSean Rhodes 	}
217*44e33a5aSSean Rhodes 
218*44e33a5aSSean Rhodes 	INIT_LIST_HEAD(&sec->attribs);
219*44e33a5aSSean Rhodes 	vpd_section_create_attribs(sec);
220*44e33a5aSSean Rhodes 
221*44e33a5aSSean Rhodes 	sec->enabled = true;
222*44e33a5aSSean Rhodes 
223*44e33a5aSSean Rhodes 	return 0;
224*44e33a5aSSean Rhodes 
225*44e33a5aSSean Rhodes err_sysfs_remove:
226*44e33a5aSSean Rhodes 	sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr);
227*44e33a5aSSean Rhodes err_free_raw_name:
228*44e33a5aSSean Rhodes 	kfree(sec->raw_name);
229*44e33a5aSSean Rhodes err_memunmap:
230*44e33a5aSSean Rhodes 	memunmap(sec->baseaddr);
231*44e33a5aSSean Rhodes 	return err;
232*44e33a5aSSean Rhodes }
233*44e33a5aSSean Rhodes 
vpd_section_destroy(struct vpd_section * sec)234*44e33a5aSSean Rhodes static int vpd_section_destroy(struct vpd_section *sec)
235*44e33a5aSSean Rhodes {
236*44e33a5aSSean Rhodes 	if (sec->enabled) {
237*44e33a5aSSean Rhodes 		vpd_section_attrib_destroy(sec);
238*44e33a5aSSean Rhodes 		kobject_put(sec->kobj);
239*44e33a5aSSean Rhodes 		sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr);
240*44e33a5aSSean Rhodes 		kfree(sec->raw_name);
241*44e33a5aSSean Rhodes 		memunmap(sec->baseaddr);
242*44e33a5aSSean Rhodes 		sec->enabled = false;
243*44e33a5aSSean Rhodes 	}
244*44e33a5aSSean Rhodes 
245*44e33a5aSSean Rhodes 	return 0;
246*44e33a5aSSean Rhodes }
247*44e33a5aSSean Rhodes 
vpd_sections_init(phys_addr_t physaddr)248*44e33a5aSSean Rhodes static int vpd_sections_init(phys_addr_t physaddr)
249*44e33a5aSSean Rhodes {
250*44e33a5aSSean Rhodes 	struct vpd_cbmem *temp;
251*44e33a5aSSean Rhodes 	struct vpd_cbmem header;
252*44e33a5aSSean Rhodes 	int ret = 0;
253*44e33a5aSSean Rhodes 
254*44e33a5aSSean Rhodes 	temp = memremap(physaddr, sizeof(struct vpd_cbmem), MEMREMAP_WB);
255*44e33a5aSSean Rhodes 	if (!temp)
256*44e33a5aSSean Rhodes 		return -ENOMEM;
257*44e33a5aSSean Rhodes 
258*44e33a5aSSean Rhodes 	memcpy(&header, temp, sizeof(struct vpd_cbmem));
259*44e33a5aSSean Rhodes 	memunmap(temp);
260*44e33a5aSSean Rhodes 
261*44e33a5aSSean Rhodes 	if (header.magic != VPD_CBMEM_MAGIC)
262*44e33a5aSSean Rhodes 		return -ENODEV;
263*44e33a5aSSean Rhodes 
264*44e33a5aSSean Rhodes 	if (header.ro_size) {
265*44e33a5aSSean Rhodes 		ret = vpd_section_init("ro", &ro_vpd,
266*44e33a5aSSean Rhodes 				       physaddr + sizeof(struct vpd_cbmem),
267*44e33a5aSSean Rhodes 				       header.ro_size);
268*44e33a5aSSean Rhodes 		if (ret)
269*44e33a5aSSean Rhodes 			return ret;
270*44e33a5aSSean Rhodes 	}
271*44e33a5aSSean Rhodes 
272*44e33a5aSSean Rhodes 	if (header.rw_size) {
273*44e33a5aSSean Rhodes 		ret = vpd_section_init("rw", &rw_vpd,
274*44e33a5aSSean Rhodes 				       physaddr + sizeof(struct vpd_cbmem) +
275*44e33a5aSSean Rhodes 				       header.ro_size, header.rw_size);
276*44e33a5aSSean Rhodes 		if (ret) {
277*44e33a5aSSean Rhodes 			vpd_section_destroy(&ro_vpd);
278*44e33a5aSSean Rhodes 			return ret;
279*44e33a5aSSean Rhodes 		}
280*44e33a5aSSean Rhodes 	}
281*44e33a5aSSean Rhodes 
282*44e33a5aSSean Rhodes 	return 0;
283*44e33a5aSSean Rhodes }
284*44e33a5aSSean Rhodes 
vpd_probe(struct coreboot_device * dev)285*44e33a5aSSean Rhodes static int vpd_probe(struct coreboot_device *dev)
286*44e33a5aSSean Rhodes {
287*44e33a5aSSean Rhodes 	int ret;
288*44e33a5aSSean Rhodes 
289*44e33a5aSSean Rhodes 	vpd_kobj = kobject_create_and_add("vpd", firmware_kobj);
290*44e33a5aSSean Rhodes 	if (!vpd_kobj)
291*44e33a5aSSean Rhodes 		return -ENOMEM;
292*44e33a5aSSean Rhodes 
293*44e33a5aSSean Rhodes 	ret = vpd_sections_init(dev->cbmem_ref.cbmem_addr);
294*44e33a5aSSean Rhodes 	if (ret) {
295*44e33a5aSSean Rhodes 		kobject_put(vpd_kobj);
296*44e33a5aSSean Rhodes 		return ret;
297*44e33a5aSSean Rhodes 	}
298*44e33a5aSSean Rhodes 
299*44e33a5aSSean Rhodes 	return 0;
300*44e33a5aSSean Rhodes }
301*44e33a5aSSean Rhodes 
vpd_remove(struct coreboot_device * dev)302*44e33a5aSSean Rhodes static void vpd_remove(struct coreboot_device *dev)
303*44e33a5aSSean Rhodes {
304*44e33a5aSSean Rhodes 	vpd_section_destroy(&ro_vpd);
305*44e33a5aSSean Rhodes 	vpd_section_destroy(&rw_vpd);
306*44e33a5aSSean Rhodes 
307*44e33a5aSSean Rhodes 	kobject_put(vpd_kobj);
308*44e33a5aSSean Rhodes }
309*44e33a5aSSean Rhodes 
310*44e33a5aSSean Rhodes static const struct coreboot_device_id vpd_ids[] = {
311*44e33a5aSSean Rhodes 	{ .tag = CB_TAG_VPD },
312*44e33a5aSSean Rhodes 	{ /* sentinel */ }
313*44e33a5aSSean Rhodes };
314*44e33a5aSSean Rhodes MODULE_DEVICE_TABLE(coreboot, vpd_ids);
315*44e33a5aSSean Rhodes 
316*44e33a5aSSean Rhodes static struct coreboot_driver vpd_driver = {
317*44e33a5aSSean Rhodes 	.probe = vpd_probe,
318*44e33a5aSSean Rhodes 	.remove = vpd_remove,
319*44e33a5aSSean Rhodes 	.drv = {
320*44e33a5aSSean Rhodes 		.name = "vpd",
321*44e33a5aSSean Rhodes 	},
322*44e33a5aSSean Rhodes 	.id_table = vpd_ids,
323*44e33a5aSSean Rhodes };
324*44e33a5aSSean Rhodes module_coreboot_driver(vpd_driver);
325*44e33a5aSSean Rhodes 
326*44e33a5aSSean Rhodes MODULE_AUTHOR("Google, Inc.");
327*44e33a5aSSean Rhodes MODULE_DESCRIPTION("Driver for exporting Vital Product Data content to sysfs");
328*44e33a5aSSean Rhodes MODULE_LICENSE("GPL");
329