Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Export Runtime Configuration Interface Table Version 2 (RCI2)
0004  * to sysfs
0005  *
0006  * Copyright (C) 2019 Dell Inc
0007  * by Narendra K <Narendra.K@dell.com>
0008  *
0009  * System firmware advertises the address of the RCI2 Table via
0010  * an EFI Configuration Table entry. This code retrieves the RCI2
0011  * table from the address and exports it to sysfs as a binary
0012  * attribute 'rci2' under /sys/firmware/efi/tables directory.
0013  */
0014 
0015 #include <linux/kobject.h>
0016 #include <linux/device.h>
0017 #include <linux/sysfs.h>
0018 #include <linux/efi.h>
0019 #include <linux/types.h>
0020 #include <linux/io.h>
0021 
0022 #define RCI_SIGNATURE   "_RC_"
0023 
0024 struct rci2_table_global_hdr {
0025     u16 type;
0026     u16 resvd0;
0027     u16 hdr_len;
0028     u8 rci2_sig[4];
0029     u16 resvd1;
0030     u32 resvd2;
0031     u32 resvd3;
0032     u8 major_rev;
0033     u8 minor_rev;
0034     u16 num_of_structs;
0035     u32 rci2_len;
0036     u16 rci2_chksum;
0037 } __packed;
0038 
0039 static u8 *rci2_base;
0040 static u32 rci2_table_len;
0041 unsigned long rci2_table_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;
0042 
0043 static ssize_t raw_table_read(struct file *file, struct kobject *kobj,
0044                   struct bin_attribute *attr, char *buf,
0045                   loff_t pos, size_t count)
0046 {
0047     memcpy(buf, attr->private + pos, count);
0048     return count;
0049 }
0050 
0051 static BIN_ATTR(rci2, S_IRUSR, raw_table_read, NULL, 0);
0052 
0053 static u16 checksum(void)
0054 {
0055     u8 len_is_odd = rci2_table_len % 2;
0056     u32 chksum_len = rci2_table_len;
0057     u16 *base = (u16 *)rci2_base;
0058     u8 buf[2] = {0};
0059     u32 offset = 0;
0060     u16 chksum = 0;
0061 
0062     if (len_is_odd)
0063         chksum_len -= 1;
0064 
0065     while (offset < chksum_len) {
0066         chksum += *base;
0067         offset += 2;
0068         base++;
0069     }
0070 
0071     if (len_is_odd) {
0072         buf[0] = *(u8 *)base;
0073         chksum += *(u16 *)(buf);
0074     }
0075 
0076     return chksum;
0077 }
0078 
0079 static int __init efi_rci2_sysfs_init(void)
0080 {
0081     struct kobject *tables_kobj;
0082     int ret = -ENOMEM;
0083 
0084     if (rci2_table_phys == EFI_INVALID_TABLE_ADDR)
0085         return 0;
0086 
0087     rci2_base = memremap(rci2_table_phys,
0088                  sizeof(struct rci2_table_global_hdr),
0089                  MEMREMAP_WB);
0090     if (!rci2_base) {
0091         pr_debug("RCI2 table init failed - could not map RCI2 table\n");
0092         goto err;
0093     }
0094 
0095     if (strncmp(rci2_base +
0096             offsetof(struct rci2_table_global_hdr, rci2_sig),
0097             RCI_SIGNATURE, 4)) {
0098         pr_debug("RCI2 table init failed - incorrect signature\n");
0099         ret = -ENODEV;
0100         goto err_unmap;
0101     }
0102 
0103     rci2_table_len = *(u32 *)(rci2_base +
0104                   offsetof(struct rci2_table_global_hdr,
0105                   rci2_len));
0106 
0107     memunmap(rci2_base);
0108 
0109     if (!rci2_table_len) {
0110         pr_debug("RCI2 table init failed - incorrect table length\n");
0111         goto err;
0112     }
0113 
0114     rci2_base = memremap(rci2_table_phys, rci2_table_len, MEMREMAP_WB);
0115     if (!rci2_base) {
0116         pr_debug("RCI2 table - could not map RCI2 table\n");
0117         goto err;
0118     }
0119 
0120     if (checksum() != 0) {
0121         pr_debug("RCI2 table - incorrect checksum\n");
0122         ret = -ENODEV;
0123         goto err_unmap;
0124     }
0125 
0126     tables_kobj = kobject_create_and_add("tables", efi_kobj);
0127     if (!tables_kobj) {
0128         pr_debug("RCI2 table - tables_kobj creation failed\n");
0129         goto err_unmap;
0130     }
0131 
0132     bin_attr_rci2.size = rci2_table_len;
0133     bin_attr_rci2.private = rci2_base;
0134     ret = sysfs_create_bin_file(tables_kobj, &bin_attr_rci2);
0135     if (ret != 0) {
0136         pr_debug("RCI2 table - rci2 sysfs bin file creation failed\n");
0137         kobject_del(tables_kobj);
0138         kobject_put(tables_kobj);
0139         goto err_unmap;
0140     }
0141 
0142     return 0;
0143 
0144  err_unmap:
0145     memunmap(rci2_base);
0146  err:
0147     pr_debug("RCI2 table - sysfs initialization failed\n");
0148     return ret;
0149 }
0150 late_initcall(efi_rci2_sysfs_init);