0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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);