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 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 */ 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 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 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 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 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 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 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 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 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 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