Hi, > From: linux-acpi-owner@xxxxxxxxxxxxxxx [mailto:linux-acpi- > owner@xxxxxxxxxxxxxxx] On Behalf Of Octavian Purdila > Subject: [RFC PATCH 10/10] acpi: add support for loading SSDTs via configfs > > Add support for acpi_user_table configfs items that allows the user to > load new tables. The data attributes contains the table data and once it > is filled from userspace the table is loaded and ACPI devices are > enumerated. [Lv Zheng] We've been considering to implement this facility before. The 2 alternative solutions are: 1. implement LOAD/UNLOAD ioctl for /sys/kernel/debug/acpi/acpidbg - this will be useful for extracting AML byte stream from kernel to be used by a userspace disassembler. 2. transition /sys/firmware/acpi/tables/xxx into directory and implement /sys/firmware/acpi/tables/load, /sys/firmware/acpi/tables/unload - this should be able to meet your requirement. So my first question is: Why do you use configfs rather than the existing mechanisms? > > Signed-off-by: Octavian Purdila <octavian.purdila@xxxxxxxxx> > --- > Documentation/ABI/testing/configfs-acpi | 16 +++++ > Documentation/acpi/ssdt-overlays.txt | 14 +++++ > drivers/acpi/configfs.c | 104 ++++++++++++++++++++++++++++++++ > 3 files changed, 134 insertions(+) > > diff --git a/Documentation/ABI/testing/configfs-acpi > b/Documentation/ABI/testing/configfs-acpi > index 0c806aa..34a205e 100644 > --- a/Documentation/ABI/testing/configfs-acpi > +++ b/Documentation/ABI/testing/configfs-acpi > @@ -5,3 +5,19 @@ Contact: linux-acpi@xxxxxxxxxxxxxxx > Description: > This represents the ACPI subsystem entry point directory. It > contains sub-groups corresponding to ACPI configurable > options. > + > +What: /config/acpi/table > +Date: April 2016 > +KernelVersion: 4.6 > +Description: > + > + This group contains the configuration for user defined ACPI > + tables. The attributes of a user define table are: > + > + data - a binary write only attribute that the user can use to > + fill in the ACPI aml definitions. Once the aml data is > + written to this file and the file is closed the table > + will be loaded and ACPI device will be enumerated. To > + check if the operation is successful the user must check > + the error code for close(). If the operation is > + successful, subsequent writes to this attribute will fail. > diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt- > overlays.txt > index 7c588be..a88a2ce 100644 > --- a/Documentation/acpi/ssdt-overlays.txt > +++ b/Documentation/acpi/ssdt-overlays.txt > @@ -158,3 +158,17 @@ tmp=$(mktemp) > /bin/echo -ne "\007\000\000\000" | cat - $filename > $tmp > dd if=$tmp of="$EFIVARFS/$name-$guid" bs=$(stat -c %s $tmp) > rm $tmp > + > +== Loading ACPI SSDTs from configfs == > + > +This option allows loading of user defined SSDTs from userspace via the > configfs > +interface. The CONFIG_ACPI_CONFIGFS option must be select and configfs > must be > +mounted. In the following examples, we assume that configfs has been > mounted in > +/config. > + > +New tables can be loading by creating new directories in /config/acpi/table/ > and > +writing the SSDT aml code in the data attribute: > + > +cd /config/acpi/table > +mkdir my_ssdt > +cat ~/ssdt.aml > my_ssdt/data [Lv Zheng] Good to see the table as a directory. So that we can put more attributes under it. Thanks -Lv > diff --git a/drivers/acpi/configfs.c b/drivers/acpi/configfs.c > index 96aa3d8..3a194806 100644 > --- a/drivers/acpi/configfs.c > +++ b/drivers/acpi/configfs.c > @@ -13,6 +13,104 @@ > #include <linux/configfs.h> > #include <linux/acpi.h> > > +static struct config_group *acpi_table_group; > + > +struct acpi_user_table { > + struct config_item cfg; > + struct acpi_table_header *table; > +}; > + > +static ssize_t acpi_table_data_write(struct config_item *cfg, > + const void *data, size_t size) > +{ > + struct acpi_table_header *header = (struct acpi_table_header *)data; > + struct acpi_user_table *table; > + int ret; > + > + table = container_of(cfg, struct acpi_user_table, cfg); > + > + if (table->table) { > + pr_err("ACPI configfs table: table already loaded\n"); > + return -EBUSY; > + } > + > + if (header->length != size) { > + pr_err("ACPI configfs table: invalid table length\n"); > + return -EINVAL; > + } > + > + if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) { > + pr_err("ACPI configfs table: invalid table signature\n"); > + return -EINVAL; > + } > + > + table = container_of(cfg, struct acpi_user_table, cfg); > + > + table->table = kmemdup(header, header->length, GFP_KERNEL); > + if (!table->table) > + return -ENOMEM; > + > + ret = acpi_load_table(table->table); > + if (ret) { > + kfree(table->table); > + table->table = NULL; > + } > + > + add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK); > + > + return ret; > +} > + > +#define MAX_ACPI_TABLE_SIZE (128 * 1024) > + > +CONFIGFS_BIN_ATTR_WO(acpi_table_, data, NULL, MAX_ACPI_TABLE_SIZE); > + > +struct configfs_bin_attribute *acpi_table_bin_attrs[] = { > + &acpi_table_attr_data, > + NULL, > +}; > + > +static struct config_item_type acpi_table_type = { > + .ct_owner = THIS_MODULE, > + .ct_bin_attrs = acpi_table_bin_attrs, > +}; > + > +static struct config_item *acpi_table_make_item(struct config_group *group, > + const char *name) > +{ > + struct acpi_user_table *table; > + > + table = kzalloc(sizeof(*table), GFP_KERNEL); > + if (!table) > + return ERR_PTR(-ENOMEM); > + > + config_item_init_type_name(&table->cfg, name, &acpi_table_type); > + return &table->cfg; > +} > + > +struct configfs_group_operations acpi_table_group_ops = { > + .make_item = acpi_table_make_item, > +}; > + > +static struct config_item_type acpi_tables_type = { > + .ct_owner = THIS_MODULE, > + .ct_group_ops = &acpi_table_group_ops, > +}; > + > +static struct config_item_type acpi_root_group_type = { > + .ct_owner = THIS_MODULE, > +}; > + > +static struct configfs_subsystem acpi_configfs = { > + .su_group = { > + .cg_item = { > + .ci_namebuf = "acpi", > + .ci_type = &acpi_root_group_type, > + }, > + }, > + .su_mutex = __MUTEX_INITIALIZER(acpi_configfs.su_mutex), > +}; > + > static int __init acpi_configfs_init(void) > { > int ret; > @@ -24,12 +122,18 @@ static int __init acpi_configfs_init(void) > if (ret) > return ret; > > + acpi_table_group = configfs_register_default_group(root, "table", > + &acpi_tables_type); > + if (IS_ERR(acpi_table_group)) > + return PTR_ERR(acpi_table_group); > + > return 0; > } > module_init(acpi_configfs_init); > > static void __exit acpi_configfs_exit(void) > { > + configfs_unregister_default_group(acpi_table_group); > configfs_unregister_subsystem(&acpi_configfs); > } > module_exit(acpi_configfs_exit); > -- > 1.9.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-acpi" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html