acpi_configfs.c 6.5 KB

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