• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Originally from efivars.c,
3  *
4  * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
5  * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
6  *
7  * This code takes all variables accessible from EFI runtime and
8  *  exports them via sysfs
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * Changelog:
25  *
26  *  17 May 2004 - Matt Domsch <Matt_Domsch@dell.com>
27  *   remove check for efi_enabled in exit
28  *   add MODULE_VERSION
29  *
30  *  26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com>
31  *   minor bug fixes
32  *
33  *  21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com)
34  *   converted driver to export variable information via sysfs
35  *   and moved to drivers/firmware directory
36  *   bumped revision number to v0.07 to reflect conversion & move
37  *
38  *  10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
39  *   fix locking per Peter Chubb's findings
40  *
41  *  25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
42  *   move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
43  *
44  *  12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
45  *   use list_for_each_safe when deleting vars.
46  *   remove ifdef CONFIG_SMP around include <linux/smp.h>
47  *   v0.04 release to linux-ia64@linuxia64.org
48  *
49  *  20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
50  *   Moved vars from /proc/efi to /proc/efi/vars, and made
51  *   efi.c own the /proc/efi directory.
52  *   v0.03 release to linux-ia64@linuxia64.org
53  *
54  *  26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
55  *   At the request of Stephane, moved ownership of /proc/efi
56  *   to efi.c, and now efivars lives under /proc/efi/vars.
57  *
58  *  12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
59  *   Feedback received from Stephane Eranian incorporated.
60  *   efivar_write() checks copy_from_user() return value.
61  *   efivar_read/write() returns proper errno.
62  *   v0.02 release to linux-ia64@linuxia64.org
63  *
64  *  26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
65  *   v0.01 release to linux-ia64@linuxia64.org
66  */
67 
68 #include <linux/efi.h>
69 #include <linux/module.h>
70 #include <linux/slab.h>
71 #include <linux/ucs2_string.h>
72 
73 #define EFIVARS_VERSION "0.08"
74 #define EFIVARS_DATE "2004-May-17"
75 
76 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
77 MODULE_DESCRIPTION("sysfs interface to EFI Variables");
78 MODULE_LICENSE("GPL");
79 MODULE_VERSION(EFIVARS_VERSION);
80 
81 LIST_HEAD(efivar_sysfs_list);
82 EXPORT_SYMBOL_GPL(efivar_sysfs_list);
83 
84 static struct kset *efivars_kset;
85 
86 static struct bin_attribute *efivars_new_var;
87 static struct bin_attribute *efivars_del_var;
88 
89 struct efivar_attribute {
90 	struct attribute attr;
91 	ssize_t (*show) (struct efivar_entry *entry, char *buf);
92 	ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
93 };
94 
95 #define EFIVAR_ATTR(_name, _mode, _show, _store) \
96 struct efivar_attribute efivar_attr_##_name = { \
97 	.attr = {.name = __stringify(_name), .mode = _mode}, \
98 	.show = _show, \
99 	.store = _store, \
100 };
101 
102 #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
103 #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
104 
105 /*
106  * Prototype for sysfs creation function
107  */
108 static int
109 efivar_create_sysfs_entry(struct efivar_entry *new_var);
110 
111 static ssize_t
efivar_guid_read(struct efivar_entry * entry,char * buf)112 efivar_guid_read(struct efivar_entry *entry, char *buf)
113 {
114 	struct efi_variable *var = &entry->var;
115 	char *str = buf;
116 
117 	if (!entry || !buf)
118 		return 0;
119 
120 	efi_guid_unparse(&var->VendorGuid, str);
121 	str += strlen(str);
122 	str += sprintf(str, "\n");
123 
124 	return str - buf;
125 }
126 
127 static ssize_t
efivar_attr_read(struct efivar_entry * entry,char * buf)128 efivar_attr_read(struct efivar_entry *entry, char *buf)
129 {
130 	struct efi_variable *var = &entry->var;
131 	char *str = buf;
132 
133 	if (!entry || !buf)
134 		return -EINVAL;
135 
136 	var->DataSize = 1024;
137 	if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
138 		return -EIO;
139 
140 	if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
141 		str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
142 	if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
143 		str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
144 	if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
145 		str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
146 	if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
147 		str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
148 	if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
149 		str += sprintf(str,
150 			"EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
151 	if (var->Attributes &
152 			EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
153 		str += sprintf(str,
154 			"EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
155 	if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
156 		str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
157 	return str - buf;
158 }
159 
160 static ssize_t
efivar_size_read(struct efivar_entry * entry,char * buf)161 efivar_size_read(struct efivar_entry *entry, char *buf)
162 {
163 	struct efi_variable *var = &entry->var;
164 	char *str = buf;
165 
166 	if (!entry || !buf)
167 		return -EINVAL;
168 
169 	var->DataSize = 1024;
170 	if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
171 		return -EIO;
172 
173 	str += sprintf(str, "0x%lx\n", var->DataSize);
174 	return str - buf;
175 }
176 
177 static ssize_t
efivar_data_read(struct efivar_entry * entry,char * buf)178 efivar_data_read(struct efivar_entry *entry, char *buf)
179 {
180 	struct efi_variable *var = &entry->var;
181 
182 	if (!entry || !buf)
183 		return -EINVAL;
184 
185 	var->DataSize = 1024;
186 	if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
187 		return -EIO;
188 
189 	memcpy(buf, var->Data, var->DataSize);
190 	return var->DataSize;
191 }
192 /*
193  * We allow each variable to be edited via rewriting the
194  * entire efi variable structure.
195  */
196 static ssize_t
efivar_store_raw(struct efivar_entry * entry,const char * buf,size_t count)197 efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
198 {
199 	struct efi_variable *new_var, *var = &entry->var;
200 	int err;
201 
202 	if (count != sizeof(struct efi_variable))
203 		return -EINVAL;
204 
205 	new_var = (struct efi_variable *)buf;
206 	/*
207 	 * If only updating the variable data, then the name
208 	 * and guid should remain the same
209 	 */
210 	if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
211 		efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
212 		printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
213 		return -EINVAL;
214 	}
215 
216 	if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
217 		printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
218 		return -EINVAL;
219 	}
220 
221 	if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
222 	    efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
223 		printk(KERN_ERR "efivars: Malformed variable content\n");
224 		return -EINVAL;
225 	}
226 
227 	memcpy(&entry->var, new_var, count);
228 
229 	err = efivar_entry_set(entry, new_var->Attributes,
230 			       new_var->DataSize, new_var->Data, false);
231 	if (err) {
232 		printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
233 		return -EIO;
234 	}
235 
236 	return count;
237 }
238 
239 static ssize_t
efivar_show_raw(struct efivar_entry * entry,char * buf)240 efivar_show_raw(struct efivar_entry *entry, char *buf)
241 {
242 	struct efi_variable *var = &entry->var;
243 
244 	if (!entry || !buf)
245 		return 0;
246 
247 	var->DataSize = 1024;
248 	if (efivar_entry_get(entry, &entry->var.Attributes,
249 			     &entry->var.DataSize, entry->var.Data))
250 		return -EIO;
251 
252 	memcpy(buf, var, sizeof(*var));
253 
254 	return sizeof(*var);
255 }
256 
257 /*
258  * Generic read/write functions that call the specific functions of
259  * the attributes...
260  */
efivar_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)261 static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
262 				char *buf)
263 {
264 	struct efivar_entry *var = to_efivar_entry(kobj);
265 	struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
266 	ssize_t ret = -EIO;
267 
268 	if (!capable(CAP_SYS_ADMIN))
269 		return -EACCES;
270 
271 	if (efivar_attr->show) {
272 		ret = efivar_attr->show(var, buf);
273 	}
274 	return ret;
275 }
276 
efivar_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)277 static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
278 				const char *buf, size_t count)
279 {
280 	struct efivar_entry *var = to_efivar_entry(kobj);
281 	struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
282 	ssize_t ret = -EIO;
283 
284 	if (!capable(CAP_SYS_ADMIN))
285 		return -EACCES;
286 
287 	if (efivar_attr->store)
288 		ret = efivar_attr->store(var, buf, count);
289 
290 	return ret;
291 }
292 
293 static const struct sysfs_ops efivar_attr_ops = {
294 	.show = efivar_attr_show,
295 	.store = efivar_attr_store,
296 };
297 
efivar_release(struct kobject * kobj)298 static void efivar_release(struct kobject *kobj)
299 {
300 	struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
301 	kfree(var);
302 }
303 
304 static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
305 static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
306 static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
307 static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
308 static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
309 
310 static struct attribute *def_attrs[] = {
311 	&efivar_attr_guid.attr,
312 	&efivar_attr_size.attr,
313 	&efivar_attr_attributes.attr,
314 	&efivar_attr_data.attr,
315 	&efivar_attr_raw_var.attr,
316 	NULL,
317 };
318 
319 static struct kobj_type efivar_ktype = {
320 	.release = efivar_release,
321 	.sysfs_ops = &efivar_attr_ops,
322 	.default_attrs = def_attrs,
323 };
324 
efivar_create(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)325 static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
326 			     struct bin_attribute *bin_attr,
327 			     char *buf, loff_t pos, size_t count)
328 {
329 	struct efi_variable *new_var = (struct efi_variable *)buf;
330 	struct efivar_entry *new_entry;
331 	int err;
332 
333 	if (!capable(CAP_SYS_ADMIN))
334 		return -EACCES;
335 
336 	if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
337 	    efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
338 		printk(KERN_ERR "efivars: Malformed variable content\n");
339 		return -EINVAL;
340 	}
341 
342 	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
343 	if (!new_entry)
344 		return -ENOMEM;
345 
346 	memcpy(&new_entry->var, new_var, sizeof(*new_var));
347 
348 	err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize,
349 			       new_var->Data, &efivar_sysfs_list);
350 	if (err) {
351 		if (err == -EEXIST)
352 			err = -EINVAL;
353 		goto out;
354 	}
355 
356 	if (efivar_create_sysfs_entry(new_entry)) {
357 		printk(KERN_WARNING "efivars: failed to create sysfs entry.\n");
358 		kfree(new_entry);
359 	}
360 	return count;
361 
362 out:
363 	kfree(new_entry);
364 	return err;
365 }
366 
efivar_delete(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)367 static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
368 			     struct bin_attribute *bin_attr,
369 			     char *buf, loff_t pos, size_t count)
370 {
371 	struct efi_variable *del_var = (struct efi_variable *)buf;
372 	struct efivar_entry *entry;
373 	int err = 0;
374 
375 	if (!capable(CAP_SYS_ADMIN))
376 		return -EACCES;
377 
378 	efivar_entry_iter_begin();
379 	entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid,
380 				  &efivar_sysfs_list, true);
381 	if (!entry)
382 		err = -EINVAL;
383 	else if (__efivar_entry_delete(entry))
384 		err = -EIO;
385 
386 	efivar_entry_iter_end();
387 
388 	if (err)
389 		return err;
390 
391 	efivar_unregister(entry);
392 
393 	/* It's dead Jim.... */
394 	return count;
395 }
396 
397 /**
398  * efivar_create_sysfs_entry - create a new entry in sysfs
399  * @new_var: efivar entry to create
400  *
401  * Returns 1 on failure, 0 on success
402  */
403 static int
efivar_create_sysfs_entry(struct efivar_entry * new_var)404 efivar_create_sysfs_entry(struct efivar_entry *new_var)
405 {
406 	int i, short_name_size;
407 	char *short_name;
408 	unsigned long variable_name_size;
409 	efi_char16_t *variable_name;
410 
411 	variable_name = new_var->var.VariableName;
412 	variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
413 
414 	/*
415 	 * Length of the variable bytes in ASCII, plus the '-' separator,
416 	 * plus the GUID, plus trailing NUL
417 	 */
418 	short_name_size = variable_name_size / sizeof(efi_char16_t)
419 				+ 1 + EFI_VARIABLE_GUID_LEN + 1;
420 
421 	short_name = kzalloc(short_name_size, GFP_KERNEL);
422 
423 	if (!short_name)
424 		return 1;
425 
426 	/* Convert Unicode to normal chars (assume top bits are 0),
427 	   ala UTF-8 */
428 	for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
429 		short_name[i] = variable_name[i] & 0xFF;
430 	}
431 	/* This is ugly, but necessary to separate one vendor's
432 	   private variables from another's.         */
433 
434 	*(short_name + strlen(short_name)) = '-';
435 	efi_guid_unparse(&new_var->var.VendorGuid,
436 			 short_name + strlen(short_name));
437 
438 	new_var->kobj.kset = efivars_kset;
439 
440 	i = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
441 				   NULL, "%s", short_name);
442 	kfree(short_name);
443 	if (i)
444 		return 1;
445 
446 	kobject_uevent(&new_var->kobj, KOBJ_ADD);
447 	efivar_entry_add(new_var, &efivar_sysfs_list);
448 
449 	return 0;
450 }
451 
452 static int
create_efivars_bin_attributes(void)453 create_efivars_bin_attributes(void)
454 {
455 	struct bin_attribute *attr;
456 	int error;
457 
458 	/* new_var */
459 	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
460 	if (!attr)
461 		return -ENOMEM;
462 
463 	attr->attr.name = "new_var";
464 	attr->attr.mode = 0200;
465 	attr->write = efivar_create;
466 	efivars_new_var = attr;
467 
468 	/* del_var */
469 	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
470 	if (!attr) {
471 		error = -ENOMEM;
472 		goto out_free;
473 	}
474 	attr->attr.name = "del_var";
475 	attr->attr.mode = 0200;
476 	attr->write = efivar_delete;
477 	efivars_del_var = attr;
478 
479 	sysfs_bin_attr_init(efivars_new_var);
480 	sysfs_bin_attr_init(efivars_del_var);
481 
482 	/* Register */
483 	error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var);
484 	if (error) {
485 		printk(KERN_ERR "efivars: unable to create new_var sysfs file"
486 			" due to error %d\n", error);
487 		goto out_free;
488 	}
489 
490 	error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var);
491 	if (error) {
492 		printk(KERN_ERR "efivars: unable to create del_var sysfs file"
493 			" due to error %d\n", error);
494 		sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
495 		goto out_free;
496 	}
497 
498 	return 0;
499 out_free:
500 	kfree(efivars_del_var);
501 	efivars_del_var = NULL;
502 	kfree(efivars_new_var);
503 	efivars_new_var = NULL;
504 	return error;
505 }
506 
efivar_update_sysfs_entry(efi_char16_t * name,efi_guid_t vendor,unsigned long name_size,void * data)507 static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor,
508 				     unsigned long name_size, void *data)
509 {
510 	struct efivar_entry *entry = data;
511 
512 	if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false))
513 		return 0;
514 
515 	memcpy(entry->var.VariableName, name, name_size);
516 	memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
517 
518 	return 1;
519 }
520 
efivar_update_sysfs_entries(struct work_struct * work)521 static void efivar_update_sysfs_entries(struct work_struct *work)
522 {
523 	struct efivar_entry *entry;
524 	int err;
525 
526 	/* Add new sysfs entries */
527 	while (1) {
528 		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
529 		if (!entry)
530 			return;
531 
532 		err = efivar_init(efivar_update_sysfs_entry, entry,
533 				  true, false, &efivar_sysfs_list);
534 		if (!err)
535 			break;
536 
537 		efivar_create_sysfs_entry(entry);
538 	}
539 
540 	kfree(entry);
541 }
542 
efivars_sysfs_callback(efi_char16_t * name,efi_guid_t vendor,unsigned long name_size,void * data)543 static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
544 				  unsigned long name_size, void *data)
545 {
546 	struct efivar_entry *entry;
547 
548 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
549 	if (!entry)
550 		return -ENOMEM;
551 
552 	memcpy(entry->var.VariableName, name, name_size);
553 	memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
554 
555 	efivar_create_sysfs_entry(entry);
556 
557 	return 0;
558 }
559 
efivar_sysfs_destroy(struct efivar_entry * entry,void * data)560 static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
561 {
562 	efivar_entry_remove(entry);
563 	efivar_unregister(entry);
564 	return 0;
565 }
566 
efivars_sysfs_exit(void)567 void efivars_sysfs_exit(void)
568 {
569 	/* Remove all entries and destroy */
570 	__efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL);
571 
572 	if (efivars_new_var)
573 		sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
574 	if (efivars_del_var)
575 		sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var);
576 	kfree(efivars_new_var);
577 	kfree(efivars_del_var);
578 	kset_unregister(efivars_kset);
579 }
580 
efivars_sysfs_init(void)581 int efivars_sysfs_init(void)
582 {
583 	struct kobject *parent_kobj = efivars_kobject();
584 	int error = 0;
585 
586 	/* No efivars has been registered yet */
587 	if (!parent_kobj)
588 		return 0;
589 
590 	printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
591 	       EFIVARS_DATE);
592 
593 	efivars_kset = kset_create_and_add("vars", NULL, parent_kobj);
594 	if (!efivars_kset) {
595 		printk(KERN_ERR "efivars: Subsystem registration failed.\n");
596 		return -ENOMEM;
597 	}
598 
599 	efivar_init(efivars_sysfs_callback, NULL, false,
600 		    true, &efivar_sysfs_list);
601 
602 	error = create_efivars_bin_attributes();
603 	if (error) {
604 		efivars_sysfs_exit();
605 		return error;
606 	}
607 
608 	INIT_WORK(&efivar_work, efivar_update_sysfs_entries);
609 
610 	return 0;
611 }
612 EXPORT_SYMBOL_GPL(efivars_sysfs_init);
613 
614 module_init(efivars_sysfs_init);
615 module_exit(efivars_sysfs_exit);
616