OSDN Git Service

Merge tag 'v3.9' into efi-for-tip2
[uclinux-h8/linux.git] / drivers / firmware / efi / efivars.c
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/ucs2_string.h>
71
72 #define EFIVARS_VERSION "0.08"
73 #define EFIVARS_DATE "2004-May-17"
74
75 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
76 MODULE_DESCRIPTION("sysfs interface to EFI Variables");
77 MODULE_LICENSE("GPL");
78 MODULE_VERSION(EFIVARS_VERSION);
79
80 LIST_HEAD(efivar_sysfs_list);
81 EXPORT_SYMBOL_GPL(efivar_sysfs_list);
82
83 static struct kset *efivars_kset;
84
85 static struct bin_attribute *efivars_new_var;
86 static struct bin_attribute *efivars_del_var;
87
88 struct efivar_attribute {
89         struct attribute attr;
90         ssize_t (*show) (struct efivar_entry *entry, char *buf);
91         ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
92 };
93
94 #define EFIVAR_ATTR(_name, _mode, _show, _store) \
95 struct efivar_attribute efivar_attr_##_name = { \
96         .attr = {.name = __stringify(_name), .mode = _mode}, \
97         .show = _show, \
98         .store = _store, \
99 };
100
101 #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
102 #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
103
104 /*
105  * Prototype for sysfs creation function
106  */
107 static int
108 efivar_create_sysfs_entry(struct efivar_entry *new_var);
109
110 static ssize_t
111 efivar_guid_read(struct efivar_entry *entry, char *buf)
112 {
113         struct efi_variable *var = &entry->var;
114         char *str = buf;
115
116         if (!entry || !buf)
117                 return 0;
118
119         efi_guid_unparse(&var->VendorGuid, str);
120         str += strlen(str);
121         str += sprintf(str, "\n");
122
123         return str - buf;
124 }
125
126 static ssize_t
127 efivar_attr_read(struct efivar_entry *entry, char *buf)
128 {
129         struct efi_variable *var = &entry->var;
130         char *str = buf;
131
132         if (!entry || !buf)
133                 return -EINVAL;
134
135         var->DataSize = 1024;
136         if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
137                 return -EIO;
138
139         if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
140                 str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
141         if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
142                 str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
143         if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
144                 str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
145         if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
146                 str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
147         if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
148                 str += sprintf(str,
149                         "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
150         if (var->Attributes &
151                         EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
152                 str += sprintf(str,
153                         "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
154         if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
155                 str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
156         return str - buf;
157 }
158
159 static ssize_t
160 efivar_size_read(struct efivar_entry *entry, char *buf)
161 {
162         struct efi_variable *var = &entry->var;
163         char *str = buf;
164
165         if (!entry || !buf)
166                 return -EINVAL;
167
168         var->DataSize = 1024;
169         if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
170                 return -EIO;
171
172         str += sprintf(str, "0x%lx\n", var->DataSize);
173         return str - buf;
174 }
175
176 static ssize_t
177 efivar_data_read(struct efivar_entry *entry, char *buf)
178 {
179         struct efi_variable *var = &entry->var;
180
181         if (!entry || !buf)
182                 return -EINVAL;
183
184         var->DataSize = 1024;
185         if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
186                 return -EIO;
187
188         memcpy(buf, var->Data, var->DataSize);
189         return var->DataSize;
190 }
191 /*
192  * We allow each variable to be edited via rewriting the
193  * entire efi variable structure.
194  */
195 static ssize_t
196 efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
197 {
198         struct efi_variable *new_var, *var = &entry->var;
199         int err;
200
201         if (count != sizeof(struct efi_variable))
202                 return -EINVAL;
203
204         new_var = (struct efi_variable *)buf;
205         /*
206          * If only updating the variable data, then the name
207          * and guid should remain the same
208          */
209         if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
210                 efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
211                 printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
212                 return -EINVAL;
213         }
214
215         if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
216                 printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
217                 return -EINVAL;
218         }
219
220         if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
221             efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
222                 printk(KERN_ERR "efivars: Malformed variable content\n");
223                 return -EINVAL;
224         }
225
226         memcpy(&entry->var, new_var, count);
227
228         err = efivar_entry_set(entry, new_var->Attributes,
229                                new_var->DataSize, new_var->Data, false);
230         if (err) {
231                 printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
232                 return -EIO;
233         }
234
235         return count;
236 }
237
238 static ssize_t
239 efivar_show_raw(struct efivar_entry *entry, char *buf)
240 {
241         struct efi_variable *var = &entry->var;
242
243         if (!entry || !buf)
244                 return 0;
245
246         var->DataSize = 1024;
247         if (efivar_entry_get(entry, &entry->var.Attributes,
248                              &entry->var.DataSize, entry->var.Data))
249                 return -EIO;
250
251         memcpy(buf, var, sizeof(*var));
252
253         return sizeof(*var);
254 }
255
256 /*
257  * Generic read/write functions that call the specific functions of
258  * the attributes...
259  */
260 static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
261                                 char *buf)
262 {
263         struct efivar_entry *var = to_efivar_entry(kobj);
264         struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
265         ssize_t ret = -EIO;
266
267         if (!capable(CAP_SYS_ADMIN))
268                 return -EACCES;
269
270         if (efivar_attr->show) {
271                 ret = efivar_attr->show(var, buf);
272         }
273         return ret;
274 }
275
276 static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
277                                 const char *buf, size_t count)
278 {
279         struct efivar_entry *var = to_efivar_entry(kobj);
280         struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
281         ssize_t ret = -EIO;
282
283         if (!capable(CAP_SYS_ADMIN))
284                 return -EACCES;
285
286         if (efivar_attr->store)
287                 ret = efivar_attr->store(var, buf, count);
288
289         return ret;
290 }
291
292 static const struct sysfs_ops efivar_attr_ops = {
293         .show = efivar_attr_show,
294         .store = efivar_attr_store,
295 };
296
297 static void efivar_release(struct kobject *kobj)
298 {
299         struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
300         kfree(var);
301 }
302
303 static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
304 static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
305 static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
306 static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
307 static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
308
309 static struct attribute *def_attrs[] = {
310         &efivar_attr_guid.attr,
311         &efivar_attr_size.attr,
312         &efivar_attr_attributes.attr,
313         &efivar_attr_data.attr,
314         &efivar_attr_raw_var.attr,
315         NULL,
316 };
317
318 static struct kobj_type efivar_ktype = {
319         .release = efivar_release,
320         .sysfs_ops = &efivar_attr_ops,
321         .default_attrs = def_attrs,
322 };
323
324 static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
325                              struct bin_attribute *bin_attr,
326                              char *buf, loff_t pos, size_t count)
327 {
328         struct efi_variable *new_var = (struct efi_variable *)buf;
329         struct efivar_entry *new_entry;
330         int err;
331
332         if (!capable(CAP_SYS_ADMIN))
333                 return -EACCES;
334
335         if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
336             efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
337                 printk(KERN_ERR "efivars: Malformed variable content\n");
338                 return -EINVAL;
339         }
340
341         new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
342         if (!new_entry)
343                 return -ENOMEM;
344
345         memcpy(&new_entry->var, new_var, sizeof(*new_var));
346
347         err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize,
348                                new_var->Data, &efivar_sysfs_list);
349         if (err) {
350                 if (err == -EEXIST)
351                         err = -EINVAL;
352                 goto out;
353         }
354
355         if (efivar_create_sysfs_entry(new_entry)) {
356                 printk(KERN_WARNING "efivars: failed to create sysfs entry.\n");
357                 kfree(new_entry);
358         }
359         return count;
360
361 out:
362         kfree(new_entry);
363         return err;
364 }
365
366 static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
367                              struct bin_attribute *bin_attr,
368                              char *buf, loff_t pos, size_t count)
369 {
370         struct efi_variable *del_var = (struct efi_variable *)buf;
371         struct efivar_entry *entry;
372         int err = 0;
373
374         if (!capable(CAP_SYS_ADMIN))
375                 return -EACCES;
376
377         efivar_entry_iter_begin();
378         entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid,
379                                   &efivar_sysfs_list, true);
380         if (!entry)
381                 err = -EINVAL;
382         else if (__efivar_entry_delete(entry))
383                 err = -EIO;
384
385         efivar_entry_iter_end();
386
387         if (err)
388                 return err;
389
390         efivar_unregister(entry);
391
392         /* It's dead Jim.... */
393         return count;
394 }
395
396 /**
397  * efivar_create_sysfs_entry - create a new entry in sysfs
398  * @new_var: efivar entry to create
399  *
400  * Returns 1 on failure, 0 on success
401  */
402 static int
403 efivar_create_sysfs_entry(struct efivar_entry *new_var)
404 {
405         int i, short_name_size;
406         char *short_name;
407         unsigned long variable_name_size;
408         efi_char16_t *variable_name;
409
410         variable_name = new_var->var.VariableName;
411         variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
412
413         /*
414          * Length of the variable bytes in ASCII, plus the '-' separator,
415          * plus the GUID, plus trailing NUL
416          */
417         short_name_size = variable_name_size / sizeof(efi_char16_t)
418                                 + 1 + EFI_VARIABLE_GUID_LEN + 1;
419
420         short_name = kzalloc(short_name_size, GFP_KERNEL);
421
422         if (!short_name) {
423                 kfree(short_name);
424                 return 1;
425         }
426
427         /* Convert Unicode to normal chars (assume top bits are 0),
428            ala UTF-8 */
429         for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
430                 short_name[i] = variable_name[i] & 0xFF;
431         }
432         /* This is ugly, but necessary to separate one vendor's
433            private variables from another's.         */
434
435         *(short_name + strlen(short_name)) = '-';
436         efi_guid_unparse(&new_var->var.VendorGuid,
437                          short_name + strlen(short_name));
438
439         new_var->kobj.kset = efivars_kset;
440
441         i = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
442                                    NULL, "%s", short_name);
443         kfree(short_name);
444         if (i)
445                 return 1;
446
447         kobject_uevent(&new_var->kobj, KOBJ_ADD);
448         efivar_entry_add(new_var, &efivar_sysfs_list);
449
450         return 0;
451 }
452
453 static int
454 create_efivars_bin_attributes(void)
455 {
456         struct bin_attribute *attr;
457         int error;
458
459         /* new_var */
460         attr = kzalloc(sizeof(*attr), GFP_KERNEL);
461         if (!attr)
462                 return -ENOMEM;
463
464         attr->attr.name = "new_var";
465         attr->attr.mode = 0200;
466         attr->write = efivar_create;
467         efivars_new_var = attr;
468
469         /* del_var */
470         attr = kzalloc(sizeof(*attr), GFP_KERNEL);
471         if (!attr) {
472                 error = -ENOMEM;
473                 goto out_free;
474         }
475         attr->attr.name = "del_var";
476         attr->attr.mode = 0200;
477         attr->write = efivar_delete;
478         efivars_del_var = attr;
479
480         sysfs_bin_attr_init(efivars_new_var);
481         sysfs_bin_attr_init(efivars_del_var);
482
483         /* Register */
484         error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var);
485         if (error) {
486                 printk(KERN_ERR "efivars: unable to create new_var sysfs file"
487                         " due to error %d\n", error);
488                 goto out_free;
489         }
490
491         error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var);
492         if (error) {
493                 printk(KERN_ERR "efivars: unable to create del_var sysfs file"
494                         " due to error %d\n", error);
495                 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
496                 goto out_free;
497         }
498
499         return 0;
500 out_free:
501         kfree(efivars_del_var);
502         efivars_del_var = NULL;
503         kfree(efivars_new_var);
504         efivars_new_var = NULL;
505         return error;
506 }
507
508 static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor,
509                                      unsigned long name_size, void *data)
510 {
511         struct efivar_entry *entry = data;
512
513         if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false))
514                 return 0;
515
516         memcpy(entry->var.VariableName, name, name_size);
517         memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
518
519         return 1;
520 }
521
522 static void efivar_update_sysfs_entries(struct work_struct *work)
523 {
524         struct efivar_entry *entry;
525         int err;
526
527         entry = kzalloc(sizeof(*entry), GFP_KERNEL);
528         if (!entry)
529                 return;
530
531         /* Add new sysfs entries */
532         while (1) {
533                 memset(entry, 0, sizeof(*entry));
534
535                 err = efivar_init(efivar_update_sysfs_entry, entry,
536                                   true, false, &efivar_sysfs_list);
537                 if (!err)
538                         break;
539
540                 efivar_create_sysfs_entry(entry);
541         }
542
543         kfree(entry);
544 }
545
546 static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
547                                   unsigned long name_size, void *data)
548 {
549         struct efivar_entry *entry;
550
551         entry = kzalloc(sizeof(*entry), GFP_KERNEL);
552         if (!entry)
553                 return -ENOMEM;
554
555         memcpy(entry->var.VariableName, name, name_size);
556         memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
557
558         efivar_create_sysfs_entry(entry);
559
560         return 0;
561 }
562
563 static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
564 {
565         efivar_entry_remove(entry);
566         efivar_unregister(entry);
567         return 0;
568 }
569
570 void efivars_sysfs_exit(void)
571 {
572         /* Remove all entries and destroy */
573         __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL);
574
575         if (efivars_new_var)
576                 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
577         if (efivars_del_var)
578                 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var);
579         kfree(efivars_new_var);
580         kfree(efivars_del_var);
581         kset_unregister(efivars_kset);
582 }
583
584 int efivars_sysfs_init(void)
585 {
586         struct kobject *parent_kobj = efivars_kobject();
587         int error = 0;
588
589         /* No efivars has been registered yet */
590         if (!parent_kobj)
591                 return 0;
592
593         printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
594                EFIVARS_DATE);
595
596         efivars_kset = kset_create_and_add("vars", NULL, parent_kobj);
597         if (!efivars_kset) {
598                 printk(KERN_ERR "efivars: Subsystem registration failed.\n");
599                 return -ENOMEM;
600         }
601
602         efivar_init(efivars_sysfs_callback, NULL, false,
603                     true, &efivar_sysfs_list);
604
605         error = create_efivars_bin_attributes();
606         if (error) {
607                 efivars_sysfs_exit();
608                 return error;
609         }
610
611         INIT_WORK(&efivar_work, efivar_update_sysfs_entries);
612
613         return 0;
614 }
615 EXPORT_SYMBOL_GPL(efivars_sysfs_init);
616
617 module_init(efivars_sysfs_init);
618 module_exit(efivars_sysfs_exit);