Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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