cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acpi_configfs.c (6679B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ACPI configfs support
      4 *
      5 * Copyright (c) 2016 Intel Corporation
      6 */
      7
      8#define pr_fmt(fmt) "ACPI configfs: " fmt
      9
     10#include <linux/init.h>
     11#include <linux/module.h>
     12#include <linux/configfs.h>
     13#include <linux/acpi.h>
     14#include <linux/security.h>
     15
     16static struct config_group *acpi_table_group;
     17
     18struct acpi_table {
     19	struct config_item cfg;
     20	struct acpi_table_header *header;
     21	u32 index;
     22};
     23
     24static ssize_t acpi_table_aml_write(struct config_item *cfg,
     25				    const void *data, size_t size)
     26{
     27	const struct acpi_table_header *header = data;
     28	struct acpi_table *table;
     29	int ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
     30
     31	if (ret)
     32		return ret;
     33
     34	table = container_of(cfg, struct acpi_table, cfg);
     35
     36	if (table->header) {
     37		pr_err("table already loaded\n");
     38		return -EBUSY;
     39	}
     40
     41	if (header->length != size) {
     42		pr_err("invalid table length\n");
     43		return -EINVAL;
     44	}
     45
     46	if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
     47		pr_err("invalid table signature\n");
     48		return -EINVAL;
     49	}
     50
     51	table = container_of(cfg, struct acpi_table, cfg);
     52
     53	table->header = kmemdup(header, header->length, GFP_KERNEL);
     54	if (!table->header)
     55		return -ENOMEM;
     56
     57	ret = acpi_load_table(table->header, &table->index);
     58	if (ret) {
     59		kfree(table->header);
     60		table->header = NULL;
     61	}
     62
     63	return ret;
     64}
     65
     66static inline struct acpi_table_header *get_header(struct config_item *cfg)
     67{
     68	struct acpi_table *table = container_of(cfg, struct acpi_table, cfg);
     69
     70	if (!table->header)
     71		pr_err("table not loaded\n");
     72
     73	return table->header ?: ERR_PTR(-EINVAL);
     74}
     75
     76static ssize_t acpi_table_aml_read(struct config_item *cfg,
     77				   void *data, size_t size)
     78{
     79	struct acpi_table_header *h = get_header(cfg);
     80
     81	if (IS_ERR(h))
     82		return PTR_ERR(h);
     83
     84	if (data)
     85		memcpy(data, h, h->length);
     86
     87	return h->length;
     88}
     89
     90#define MAX_ACPI_TABLE_SIZE (128 * 1024)
     91
     92CONFIGFS_BIN_ATTR(acpi_table_, aml, NULL, MAX_ACPI_TABLE_SIZE);
     93
     94static struct configfs_bin_attribute *acpi_table_bin_attrs[] = {
     95	&acpi_table_attr_aml,
     96	NULL,
     97};
     98
     99static ssize_t acpi_table_signature_show(struct config_item *cfg, char *str)
    100{
    101	struct acpi_table_header *h = get_header(cfg);
    102
    103	if (IS_ERR(h))
    104		return PTR_ERR(h);
    105
    106	return sysfs_emit(str, "%.*s\n", ACPI_NAMESEG_SIZE, h->signature);
    107}
    108
    109static ssize_t acpi_table_length_show(struct config_item *cfg, char *str)
    110{
    111	struct acpi_table_header *h = get_header(cfg);
    112
    113	if (IS_ERR(h))
    114		return PTR_ERR(h);
    115
    116	return sysfs_emit(str, "%d\n", h->length);
    117}
    118
    119static ssize_t acpi_table_revision_show(struct config_item *cfg, char *str)
    120{
    121	struct acpi_table_header *h = get_header(cfg);
    122
    123	if (IS_ERR(h))
    124		return PTR_ERR(h);
    125
    126	return sysfs_emit(str, "%d\n", h->revision);
    127}
    128
    129static ssize_t acpi_table_oem_id_show(struct config_item *cfg, char *str)
    130{
    131	struct acpi_table_header *h = get_header(cfg);
    132
    133	if (IS_ERR(h))
    134		return PTR_ERR(h);
    135
    136	return sysfs_emit(str, "%.*s\n", ACPI_OEM_ID_SIZE, h->oem_id);
    137}
    138
    139static ssize_t acpi_table_oem_table_id_show(struct config_item *cfg, char *str)
    140{
    141	struct acpi_table_header *h = get_header(cfg);
    142
    143	if (IS_ERR(h))
    144		return PTR_ERR(h);
    145
    146	return sysfs_emit(str, "%.*s\n", ACPI_OEM_TABLE_ID_SIZE, h->oem_table_id);
    147}
    148
    149static ssize_t acpi_table_oem_revision_show(struct config_item *cfg, char *str)
    150{
    151	struct acpi_table_header *h = get_header(cfg);
    152
    153	if (IS_ERR(h))
    154		return PTR_ERR(h);
    155
    156	return sysfs_emit(str, "%d\n", h->oem_revision);
    157}
    158
    159static ssize_t acpi_table_asl_compiler_id_show(struct config_item *cfg,
    160					       char *str)
    161{
    162	struct acpi_table_header *h = get_header(cfg);
    163
    164	if (IS_ERR(h))
    165		return PTR_ERR(h);
    166
    167	return sysfs_emit(str, "%.*s\n", ACPI_NAMESEG_SIZE, h->asl_compiler_id);
    168}
    169
    170static ssize_t acpi_table_asl_compiler_revision_show(struct config_item *cfg,
    171						     char *str)
    172{
    173	struct acpi_table_header *h = get_header(cfg);
    174
    175	if (IS_ERR(h))
    176		return PTR_ERR(h);
    177
    178	return sysfs_emit(str, "%d\n", h->asl_compiler_revision);
    179}
    180
    181CONFIGFS_ATTR_RO(acpi_table_, signature);
    182CONFIGFS_ATTR_RO(acpi_table_, length);
    183CONFIGFS_ATTR_RO(acpi_table_, revision);
    184CONFIGFS_ATTR_RO(acpi_table_, oem_id);
    185CONFIGFS_ATTR_RO(acpi_table_, oem_table_id);
    186CONFIGFS_ATTR_RO(acpi_table_, oem_revision);
    187CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_id);
    188CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_revision);
    189
    190static struct configfs_attribute *acpi_table_attrs[] = {
    191	&acpi_table_attr_signature,
    192	&acpi_table_attr_length,
    193	&acpi_table_attr_revision,
    194	&acpi_table_attr_oem_id,
    195	&acpi_table_attr_oem_table_id,
    196	&acpi_table_attr_oem_revision,
    197	&acpi_table_attr_asl_compiler_id,
    198	&acpi_table_attr_asl_compiler_revision,
    199	NULL,
    200};
    201
    202static const struct config_item_type acpi_table_type = {
    203	.ct_owner = THIS_MODULE,
    204	.ct_bin_attrs = acpi_table_bin_attrs,
    205	.ct_attrs = acpi_table_attrs,
    206};
    207
    208static struct config_item *acpi_table_make_item(struct config_group *group,
    209						const char *name)
    210{
    211	struct acpi_table *table;
    212
    213	table = kzalloc(sizeof(*table), GFP_KERNEL);
    214	if (!table)
    215		return ERR_PTR(-ENOMEM);
    216
    217	config_item_init_type_name(&table->cfg, name, &acpi_table_type);
    218	return &table->cfg;
    219}
    220
    221static void acpi_table_drop_item(struct config_group *group,
    222				 struct config_item *cfg)
    223{
    224	struct acpi_table *table = container_of(cfg, struct acpi_table, cfg);
    225
    226	pr_debug("Host-directed Dynamic ACPI Table Unload\n");
    227	acpi_unload_table(table->index);
    228	config_item_put(cfg);
    229}
    230
    231static struct configfs_group_operations acpi_table_group_ops = {
    232	.make_item = acpi_table_make_item,
    233	.drop_item = acpi_table_drop_item,
    234};
    235
    236static const struct config_item_type acpi_tables_type = {
    237	.ct_owner = THIS_MODULE,
    238	.ct_group_ops = &acpi_table_group_ops,
    239};
    240
    241static const struct config_item_type acpi_root_group_type = {
    242	.ct_owner = THIS_MODULE,
    243};
    244
    245static struct configfs_subsystem acpi_configfs = {
    246	.su_group = {
    247		.cg_item = {
    248			.ci_namebuf = "acpi",
    249			.ci_type = &acpi_root_group_type,
    250		},
    251	},
    252	.su_mutex = __MUTEX_INITIALIZER(acpi_configfs.su_mutex),
    253};
    254
    255static int __init acpi_configfs_init(void)
    256{
    257	int ret;
    258	struct config_group *root = &acpi_configfs.su_group;
    259
    260	config_group_init(root);
    261
    262	ret = configfs_register_subsystem(&acpi_configfs);
    263	if (ret)
    264		return ret;
    265
    266	acpi_table_group = configfs_register_default_group(root, "table",
    267							   &acpi_tables_type);
    268	if (IS_ERR(acpi_table_group)) {
    269		configfs_unregister_subsystem(&acpi_configfs);
    270		return PTR_ERR(acpi_table_group);
    271	}
    272
    273	return 0;
    274}
    275module_init(acpi_configfs_init);
    276
    277static void __exit acpi_configfs_exit(void)
    278{
    279	configfs_unregister_default_group(acpi_table_group);
    280	configfs_unregister_subsystem(&acpi_configfs);
    281}
    282module_exit(acpi_configfs_exit);
    283
    284MODULE_AUTHOR("Octavian Purdila <octavian.purdila@intel.com>");
    285MODULE_DESCRIPTION("ACPI configfs support");
    286MODULE_LICENSE("GPL v2");