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 v4.20-rc2 754 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_to_str() 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_to_str(&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(vendor, name, data, size) == false) { 225 printk(KERN_ERR "efivars: Malformed variable content\n"); 226 return -EINVAL; 227 } 228 229 return 0; 230} 231 232static void 233copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src) 234{ 235 memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN); 236 memcpy(dst->Data, src->Data, sizeof(src->Data)); 237 238 dst->VendorGuid = src->VendorGuid; 239 dst->DataSize = src->DataSize; 240 dst->Attributes = src->Attributes; 241} 242 243/* 244 * We allow each variable to be edited via rewriting the 245 * entire efi variable structure. 246 */ 247static ssize_t 248efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) 249{ 250 struct efi_variable *new_var, *var = &entry->var; 251 efi_char16_t *name; 252 unsigned long size; 253 efi_guid_t vendor; 254 u32 attributes; 255 u8 *data; 256 int err; 257 258 if (in_compat_syscall()) { 259 struct compat_efi_variable *compat; 260 261 if (count != sizeof(*compat)) 262 return -EINVAL; 263 264 compat = (struct compat_efi_variable *)buf; 265 attributes = compat->Attributes; 266 vendor = compat->VendorGuid; 267 name = compat->VariableName; 268 size = compat->DataSize; 269 data = compat->Data; 270 271 err = sanity_check(var, name, vendor, size, attributes, data); 272 if (err) 273 return err; 274 275 copy_out_compat(&entry->var, compat); 276 } else { 277 if (count != sizeof(struct efi_variable)) 278 return -EINVAL; 279 280 new_var = (struct efi_variable *)buf; 281 282 attributes = new_var->Attributes; 283 vendor = new_var->VendorGuid; 284 name = new_var->VariableName; 285 size = new_var->DataSize; 286 data = new_var->Data; 287 288 err = sanity_check(var, name, vendor, size, attributes, data); 289 if (err) 290 return err; 291 292 memcpy(&entry->var, new_var, count); 293 } 294 295 err = efivar_entry_set(entry, attributes, size, data, NULL); 296 if (err) { 297 printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); 298 return -EIO; 299 } 300 301 return count; 302} 303 304static ssize_t 305efivar_show_raw(struct efivar_entry *entry, char *buf) 306{ 307 struct efi_variable *var = &entry->var; 308 struct compat_efi_variable *compat; 309 size_t size; 310 311 if (!entry || !buf) 312 return 0; 313 314 var->DataSize = 1024; 315 if (efivar_entry_get(entry, &entry->var.Attributes, 316 &entry->var.DataSize, entry->var.Data)) 317 return -EIO; 318 319 if (in_compat_syscall()) { 320 compat = (struct compat_efi_variable *)buf; 321 322 size = sizeof(*compat); 323 memcpy(compat->VariableName, var->VariableName, 324 EFI_VAR_NAME_LEN); 325 memcpy(compat->Data, var->Data, sizeof(compat->Data)); 326 327 compat->VendorGuid = var->VendorGuid; 328 compat->DataSize = var->DataSize; 329 compat->Attributes = var->Attributes; 330 } else { 331 size = sizeof(*var); 332 memcpy(buf, var, size); 333 } 334 335 return size; 336} 337 338/* 339 * Generic read/write functions that call the specific functions of 340 * the attributes... 341 */ 342static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr, 343 char *buf) 344{ 345 struct efivar_entry *var = to_efivar_entry(kobj); 346 struct efivar_attribute *efivar_attr = to_efivar_attr(attr); 347 ssize_t ret = -EIO; 348 349 if (!capable(CAP_SYS_ADMIN)) 350 return -EACCES; 351 352 if (efivar_attr->show) { 353 ret = efivar_attr->show(var, buf); 354 } 355 return ret; 356} 357 358static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, 359 const char *buf, size_t count) 360{ 361 struct efivar_entry *var = to_efivar_entry(kobj); 362 struct efivar_attribute *efivar_attr = to_efivar_attr(attr); 363 ssize_t ret = -EIO; 364 365 if (!capable(CAP_SYS_ADMIN)) 366 return -EACCES; 367 368 if (efivar_attr->store) 369 ret = efivar_attr->store(var, buf, count); 370 371 return ret; 372} 373 374static const struct sysfs_ops efivar_attr_ops = { 375 .show = efivar_attr_show, 376 .store = efivar_attr_store, 377}; 378 379static void efivar_release(struct kobject *kobj) 380{ 381 struct efivar_entry *var = to_efivar_entry(kobj); 382 kfree(var); 383} 384 385static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL); 386static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL); 387static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL); 388static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL); 389static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw); 390 391static struct attribute *def_attrs[] = { 392 &efivar_attr_guid.attr, 393 &efivar_attr_size.attr, 394 &efivar_attr_attributes.attr, 395 &efivar_attr_data.attr, 396 &efivar_attr_raw_var.attr, 397 NULL, 398}; 399 400static struct kobj_type efivar_ktype = { 401 .release = efivar_release, 402 .sysfs_ops = &efivar_attr_ops, 403 .default_attrs = def_attrs, 404}; 405 406static ssize_t efivar_create(struct file *filp, struct kobject *kobj, 407 struct bin_attribute *bin_attr, 408 char *buf, loff_t pos, size_t count) 409{ 410 struct compat_efi_variable *compat = (struct compat_efi_variable *)buf; 411 struct efi_variable *new_var = (struct efi_variable *)buf; 412 struct efivar_entry *new_entry; 413 bool need_compat = in_compat_syscall(); 414 efi_char16_t *name; 415 unsigned long size; 416 u32 attributes; 417 u8 *data; 418 int err; 419 420 if (!capable(CAP_SYS_ADMIN)) 421 return -EACCES; 422 423 if (need_compat) { 424 if (count != sizeof(*compat)) 425 return -EINVAL; 426 427 attributes = compat->Attributes; 428 name = compat->VariableName; 429 size = compat->DataSize; 430 data = compat->Data; 431 } else { 432 if (count != sizeof(*new_var)) 433 return -EINVAL; 434 435 attributes = new_var->Attributes; 436 name = new_var->VariableName; 437 size = new_var->DataSize; 438 data = new_var->Data; 439 } 440 441 if ((attributes & ~EFI_VARIABLE_MASK) != 0 || 442 efivar_validate(new_var->VendorGuid, name, data, 443 size) == false) { 444 printk(KERN_ERR "efivars: Malformed variable content\n"); 445 return -EINVAL; 446 } 447 448 new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); 449 if (!new_entry) 450 return -ENOMEM; 451 452 if (need_compat) 453 copy_out_compat(&new_entry->var, compat); 454 else 455 memcpy(&new_entry->var, new_var, sizeof(*new_var)); 456 457 err = efivar_entry_set(new_entry, attributes, size, 458 data, &efivar_sysfs_list); 459 if (err) { 460 if (err == -EEXIST) 461 err = -EINVAL; 462 goto out; 463 } 464 465 if (efivar_create_sysfs_entry(new_entry)) { 466 printk(KERN_WARNING "efivars: failed to create sysfs entry.\n"); 467 kfree(new_entry); 468 } 469 return count; 470 471out: 472 kfree(new_entry); 473 return err; 474} 475 476static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, 477 struct bin_attribute *bin_attr, 478 char *buf, loff_t pos, size_t count) 479{ 480 struct efi_variable *del_var = (struct efi_variable *)buf; 481 struct compat_efi_variable *compat; 482 struct efivar_entry *entry; 483 efi_char16_t *name; 484 efi_guid_t vendor; 485 int err = 0; 486 487 if (!capable(CAP_SYS_ADMIN)) 488 return -EACCES; 489 490 if (in_compat_syscall()) { 491 if (count != sizeof(*compat)) 492 return -EINVAL; 493 494 compat = (struct compat_efi_variable *)buf; 495 name = compat->VariableName; 496 vendor = compat->VendorGuid; 497 } else { 498 if (count != sizeof(*del_var)) 499 return -EINVAL; 500 501 name = del_var->VariableName; 502 vendor = del_var->VendorGuid; 503 } 504 505 if (efivar_entry_iter_begin()) 506 return -EINTR; 507 entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true); 508 if (!entry) 509 err = -EINVAL; 510 else if (__efivar_entry_delete(entry)) 511 err = -EIO; 512 513 if (err) { 514 efivar_entry_iter_end(); 515 return err; 516 } 517 518 if (!entry->scanning) { 519 efivar_entry_iter_end(); 520 efivar_unregister(entry); 521 } else 522 efivar_entry_iter_end(); 523 524 /* It's dead Jim.... */ 525 return count; 526} 527 528/** 529 * efivar_create_sysfs_entry - create a new entry in sysfs 530 * @new_var: efivar entry to create 531 * 532 * Returns 0 on success, negative error code on failure 533 */ 534static int 535efivar_create_sysfs_entry(struct efivar_entry *new_var) 536{ 537 int short_name_size; 538 char *short_name; 539 unsigned long utf8_name_size; 540 efi_char16_t *variable_name = new_var->var.VariableName; 541 int ret; 542 543 /* 544 * Length of the variable bytes in UTF8, plus the '-' separator, 545 * plus the GUID, plus trailing NUL 546 */ 547 utf8_name_size = ucs2_utf8size(variable_name); 548 short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1; 549 550 short_name = kmalloc(short_name_size, GFP_KERNEL); 551 if (!short_name) 552 return -ENOMEM; 553 554 ucs2_as_utf8(short_name, variable_name, short_name_size); 555 556 /* This is ugly, but necessary to separate one vendor's 557 private variables from another's. */ 558 short_name[utf8_name_size] = '-'; 559 efi_guid_to_str(&new_var->var.VendorGuid, 560 short_name + utf8_name_size + 1); 561 562 new_var->kobj.kset = efivars_kset; 563 564 ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype, 565 NULL, "%s", short_name); 566 kfree(short_name); 567 if (ret) 568 return ret; 569 570 kobject_uevent(&new_var->kobj, KOBJ_ADD); 571 if (efivar_entry_add(new_var, &efivar_sysfs_list)) { 572 efivar_unregister(new_var); 573 return -EINTR; 574 } 575 576 return 0; 577} 578 579static int 580create_efivars_bin_attributes(void) 581{ 582 struct bin_attribute *attr; 583 int error; 584 585 /* new_var */ 586 attr = kzalloc(sizeof(*attr), GFP_KERNEL); 587 if (!attr) 588 return -ENOMEM; 589 590 attr->attr.name = "new_var"; 591 attr->attr.mode = 0200; 592 attr->write = efivar_create; 593 efivars_new_var = attr; 594 595 /* del_var */ 596 attr = kzalloc(sizeof(*attr), GFP_KERNEL); 597 if (!attr) { 598 error = -ENOMEM; 599 goto out_free; 600 } 601 attr->attr.name = "del_var"; 602 attr->attr.mode = 0200; 603 attr->write = efivar_delete; 604 efivars_del_var = attr; 605 606 sysfs_bin_attr_init(efivars_new_var); 607 sysfs_bin_attr_init(efivars_del_var); 608 609 /* Register */ 610 error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var); 611 if (error) { 612 printk(KERN_ERR "efivars: unable to create new_var sysfs file" 613 " due to error %d\n", error); 614 goto out_free; 615 } 616 617 error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var); 618 if (error) { 619 printk(KERN_ERR "efivars: unable to create del_var sysfs file" 620 " due to error %d\n", error); 621 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); 622 goto out_free; 623 } 624 625 return 0; 626out_free: 627 kfree(efivars_del_var); 628 efivars_del_var = NULL; 629 kfree(efivars_new_var); 630 efivars_new_var = NULL; 631 return error; 632} 633 634static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor, 635 unsigned long name_size, void *data) 636{ 637 struct efivar_entry *entry = data; 638 639 if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false)) 640 return 0; 641 642 memcpy(entry->var.VariableName, name, name_size); 643 memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); 644 645 return 1; 646} 647 648static void efivar_update_sysfs_entries(struct work_struct *work) 649{ 650 struct efivar_entry *entry; 651 int err; 652 653 /* Add new sysfs entries */ 654 while (1) { 655 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 656 if (!entry) 657 return; 658 659 err = efivar_init(efivar_update_sysfs_entry, entry, 660 false, &efivar_sysfs_list); 661 if (!err) 662 break; 663 664 efivar_create_sysfs_entry(entry); 665 } 666 667 kfree(entry); 668} 669 670static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor, 671 unsigned long name_size, void *data) 672{ 673 struct efivar_entry *entry; 674 675 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 676 if (!entry) 677 return -ENOMEM; 678 679 memcpy(entry->var.VariableName, name, name_size); 680 memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); 681 682 efivar_create_sysfs_entry(entry); 683 684 return 0; 685} 686 687static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) 688{ 689 int err = efivar_entry_remove(entry); 690 691 if (err) 692 return err; 693 efivar_unregister(entry); 694 return 0; 695} 696 697static void efivars_sysfs_exit(void) 698{ 699 /* Remove all entries and destroy */ 700 int err; 701 702 err = __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, 703 NULL, NULL); 704 if (err) { 705 pr_err("efivars: Failed to destroy sysfs entries\n"); 706 return; 707 } 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, 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);