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