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