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