brintos

brintos / linux-shallow public Read only

0
0
Text · 3.0 KiB · 4fd45d6 Raw
143 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Export Runtime Configuration Interface Table Version 2 (RCI2)4 * to sysfs5 *6 * Copyright (C) 2019 Dell Inc7 * by Narendra K <Narendra.K@dell.com>8 *9 * System firmware advertises the address of the RCI2 Table via10 * an EFI Configuration Table entry. This code retrieves the RCI211 * table from the address and exports it to sysfs as a binary12 * attribute 'rci2' under /sys/firmware/efi/tables directory.13 */14 15#include <linux/kobject.h>16#include <linux/device.h>17#include <linux/sysfs.h>18#include <linux/efi.h>19#include <linux/types.h>20#include <linux/io.h>21 22#define RCI_SIGNATURE	"_RC_"23 24struct rci2_table_global_hdr {25	u16 type;26	u16 resvd0;27	u16 hdr_len;28	u8 rci2_sig[4];29	u16 resvd1;30	u32 resvd2;31	u32 resvd3;32	u8 major_rev;33	u8 minor_rev;34	u16 num_of_structs;35	u32 rci2_len;36	u16 rci2_chksum;37} __packed;38 39static u8 *rci2_base;40static u32 rci2_table_len;41unsigned long rci2_table_phys __ro_after_init = EFI_INVALID_TABLE_ADDR;42 43static BIN_ATTR_SIMPLE_ADMIN_RO(rci2);44 45static u16 checksum(void)46{47	u8 len_is_odd = rci2_table_len % 2;48	u32 chksum_len = rci2_table_len;49	u16 *base = (u16 *)rci2_base;50	u8 buf[2] = {0};51	u32 offset = 0;52	u16 chksum = 0;53 54	if (len_is_odd)55		chksum_len -= 1;56 57	while (offset < chksum_len) {58		chksum += *base;59		offset += 2;60		base++;61	}62 63	if (len_is_odd) {64		buf[0] = *(u8 *)base;65		chksum += *(u16 *)(buf);66	}67 68	return chksum;69}70 71static int __init efi_rci2_sysfs_init(void)72{73	struct kobject *tables_kobj;74	int ret = -ENOMEM;75 76	if (rci2_table_phys == EFI_INVALID_TABLE_ADDR)77		return 0;78 79	rci2_base = memremap(rci2_table_phys,80			     sizeof(struct rci2_table_global_hdr),81			     MEMREMAP_WB);82	if (!rci2_base) {83		pr_debug("RCI2 table init failed - could not map RCI2 table\n");84		goto err;85	}86 87	if (strncmp(rci2_base +88		    offsetof(struct rci2_table_global_hdr, rci2_sig),89		    RCI_SIGNATURE, 4)) {90		pr_debug("RCI2 table init failed - incorrect signature\n");91		ret = -ENODEV;92		goto err_unmap;93	}94 95	rci2_table_len = *(u32 *)(rci2_base +96				  offsetof(struct rci2_table_global_hdr,97				  rci2_len));98 99	memunmap(rci2_base);100 101	if (!rci2_table_len) {102		pr_debug("RCI2 table init failed - incorrect table length\n");103		goto err;104	}105 106	rci2_base = memremap(rci2_table_phys, rci2_table_len, MEMREMAP_WB);107	if (!rci2_base) {108		pr_debug("RCI2 table - could not map RCI2 table\n");109		goto err;110	}111 112	if (checksum() != 0) {113		pr_debug("RCI2 table - incorrect checksum\n");114		ret = -ENODEV;115		goto err_unmap;116	}117 118	tables_kobj = kobject_create_and_add("tables", efi_kobj);119	if (!tables_kobj) {120		pr_debug("RCI2 table - tables_kobj creation failed\n");121		goto err_unmap;122	}123 124	bin_attr_rci2.size = rci2_table_len;125	bin_attr_rci2.private = rci2_base;126	ret = sysfs_create_bin_file(tables_kobj, &bin_attr_rci2);127	if (ret != 0) {128		pr_debug("RCI2 table - rci2 sysfs bin file creation failed\n");129		kobject_del(tables_kobj);130		kobject_put(tables_kobj);131		goto err_unmap;132	}133 134	return 0;135 136 err_unmap:137	memunmap(rci2_base);138 err:139	pr_debug("RCI2 table - sysfs initialization failed\n");140	return ret;141}142late_initcall(efi_rci2_sysfs_init);143