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