diff options
-rw-r--r-- | drivers/firmware/efivars.c | 1819 | ||||
-rw-r--r-- | drivers/firmware/google/gsmi.c | 11 | ||||
-rw-r--r-- | include/linux/efi.h | 76 |
3 files changed, 1176 insertions, 730 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index eab4ec41c523..82fd145ead3b 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
@@ -97,39 +97,14 @@ MODULE_VERSION(EFIVARS_VERSION); | |||
97 | 97 | ||
98 | #define DUMP_NAME_LEN 52 | 98 | #define DUMP_NAME_LEN 52 |
99 | 99 | ||
100 | /* | 100 | static LIST_HEAD(efivarfs_list); |
101 | * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")) | 101 | static LIST_HEAD(efivar_sysfs_list); |
102 | * not including trailing NUL | ||
103 | */ | ||
104 | #define GUID_LEN 36 | ||
105 | 102 | ||
106 | static bool efivars_pstore_disable = | 103 | static bool efivars_pstore_disable = |
107 | IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); | 104 | IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); |
108 | 105 | ||
109 | module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); | 106 | module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); |
110 | 107 | ||
111 | /* | ||
112 | * The maximum size of VariableName + Data = 1024 | ||
113 | * Therefore, it's reasonable to save that much | ||
114 | * space in each part of the structure, | ||
115 | * and we use a page for reading/writing. | ||
116 | */ | ||
117 | |||
118 | struct efi_variable { | ||
119 | efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; | ||
120 | efi_guid_t VendorGuid; | ||
121 | unsigned long DataSize; | ||
122 | __u8 Data[1024]; | ||
123 | efi_status_t Status; | ||
124 | __u32 Attributes; | ||
125 | } __attribute__((packed)); | ||
126 | |||
127 | struct efivar_entry { | ||
128 | struct efi_variable var; | ||
129 | struct list_head list; | ||
130 | struct kobject kobj; | ||
131 | }; | ||
132 | |||
133 | struct efivar_attribute { | 108 | struct efivar_attribute { |
134 | struct attribute attr; | 109 | struct attribute attr; |
135 | ssize_t (*show) (struct efivar_entry *entry, char *buf); | 110 | ssize_t (*show) (struct efivar_entry *entry, char *buf); |
@@ -144,6 +119,11 @@ static struct efivars *__efivars; | |||
144 | EFI_VARIABLE_BOOTSERVICE_ACCESS | \ | 119 | EFI_VARIABLE_BOOTSERVICE_ACCESS | \ |
145 | EFI_VARIABLE_RUNTIME_ACCESS) | 120 | EFI_VARIABLE_RUNTIME_ACCESS) |
146 | 121 | ||
122 | static struct kset *efivars_kset; | ||
123 | |||
124 | static struct bin_attribute *efivars_new_var; | ||
125 | static struct bin_attribute *efivars_del_var; | ||
126 | |||
147 | #define EFIVAR_ATTR(_name, _mode, _show, _store) \ | 127 | #define EFIVAR_ATTR(_name, _mode, _show, _store) \ |
148 | struct efivar_attribute efivar_attr_##_name = { \ | 128 | struct efivar_attribute efivar_attr_##_name = { \ |
149 | .attr = {.name = __stringify(_name), .mode = _mode}, \ | 129 | .attr = {.name = __stringify(_name), .mode = _mode}, \ |
@@ -158,10 +138,7 @@ struct efivar_attribute efivar_attr_##_name = { \ | |||
158 | * Prototype for sysfs creation function | 138 | * Prototype for sysfs creation function |
159 | */ | 139 | */ |
160 | static int | 140 | static int |
161 | efivar_create_sysfs_entry(struct efivars *efivars, | 141 | efivar_create_sysfs_entry(struct efivar_entry *new_var); |
162 | unsigned long variable_name_size, | ||
163 | efi_char16_t *variable_name, | ||
164 | efi_guid_t *vendor_guid); | ||
165 | 142 | ||
166 | /* | 143 | /* |
167 | * Prototype for workqueue functions updating sysfs entry | 144 | * Prototype for workqueue functions updating sysfs entry |
@@ -346,8 +323,8 @@ static const struct variable_validate variable_validate[] = { | |||
346 | { "", NULL }, | 323 | { "", NULL }, |
347 | }; | 324 | }; |
348 | 325 | ||
349 | static bool | 326 | bool |
350 | validate_var(struct efi_variable *var, u8 *data, unsigned long len) | 327 | efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) |
351 | { | 328 | { |
352 | int i; | 329 | int i; |
353 | u16 *unicode_name = var->VariableName; | 330 | u16 *unicode_name = var->VariableName; |
@@ -382,47 +359,16 @@ validate_var(struct efi_variable *var, u8 *data, unsigned long len) | |||
382 | 359 | ||
383 | return true; | 360 | return true; |
384 | } | 361 | } |
362 | EXPORT_SYMBOL_GPL(efivar_validate); | ||
385 | 363 | ||
386 | static efi_status_t | 364 | static efi_status_t |
387 | get_var_data_locked(struct efivars *efivars, struct efi_variable *var) | 365 | check_var_size(u32 attributes, unsigned long size) |
388 | { | ||
389 | efi_status_t status; | ||
390 | |||
391 | var->DataSize = 1024; | ||
392 | status = efivars->ops->get_variable(var->VariableName, | ||
393 | &var->VendorGuid, | ||
394 | &var->Attributes, | ||
395 | &var->DataSize, | ||
396 | var->Data); | ||
397 | return status; | ||
398 | } | ||
399 | |||
400 | static efi_status_t | ||
401 | get_var_data(struct efivars *efivars, struct efi_variable *var) | ||
402 | { | ||
403 | efi_status_t status; | ||
404 | unsigned long flags; | ||
405 | |||
406 | spin_lock_irqsave(&efivars->lock, flags); | ||
407 | status = get_var_data_locked(efivars, var); | ||
408 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
409 | |||
410 | if (status != EFI_SUCCESS) { | ||
411 | printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n", | ||
412 | status); | ||
413 | } | ||
414 | return status; | ||
415 | } | ||
416 | |||
417 | static efi_status_t | ||
418 | check_var_size_locked(struct efivars *efivars, u32 attributes, | ||
419 | unsigned long size) | ||
420 | { | 366 | { |
421 | u64 storage_size, remaining_size, max_size; | 367 | u64 storage_size, remaining_size, max_size; |
422 | efi_status_t status; | 368 | efi_status_t status; |
423 | const struct efivar_operations *fops = efivars->ops; | 369 | const struct efivar_operations *fops = __efivars->ops; |
424 | 370 | ||
425 | if (!efivars->ops->query_variable_info) | 371 | if (!fops->query_variable_info) |
426 | return EFI_UNSUPPORTED; | 372 | return EFI_UNSUPPORTED; |
427 | 373 | ||
428 | status = fops->query_variable_info(attributes, &storage_size, | 374 | status = fops->query_variable_info(attributes, &storage_size, |
@@ -438,20 +384,6 @@ check_var_size_locked(struct efivars *efivars, u32 attributes, | |||
438 | return status; | 384 | return status; |
439 | } | 385 | } |
440 | 386 | ||
441 | |||
442 | static efi_status_t | ||
443 | check_var_size(struct efivars *efivars, u32 attributes, unsigned long size) | ||
444 | { | ||
445 | efi_status_t status; | ||
446 | unsigned long flags; | ||
447 | |||
448 | spin_lock_irqsave(&efivars->lock, flags); | ||
449 | status = check_var_size_locked(efivars, attributes, size); | ||
450 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
451 | |||
452 | return status; | ||
453 | } | ||
454 | |||
455 | static ssize_t | 387 | static ssize_t |
456 | efivar_guid_read(struct efivar_entry *entry, char *buf) | 388 | efivar_guid_read(struct efivar_entry *entry, char *buf) |
457 | { | 389 | { |
@@ -473,13 +405,12 @@ efivar_attr_read(struct efivar_entry *entry, char *buf) | |||
473 | { | 405 | { |
474 | struct efi_variable *var = &entry->var; | 406 | struct efi_variable *var = &entry->var; |
475 | char *str = buf; | 407 | char *str = buf; |
476 | efi_status_t status; | ||
477 | 408 | ||
478 | if (!entry || !buf) | 409 | if (!entry || !buf) |
479 | return -EINVAL; | 410 | return -EINVAL; |
480 | 411 | ||
481 | status = get_var_data(__efivars, var); | 412 | var->DataSize = 1024; |
482 | if (status != EFI_SUCCESS) | 413 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) |
483 | return -EIO; | 414 | return -EIO; |
484 | 415 | ||
485 | if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) | 416 | if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) |
@@ -507,13 +438,12 @@ efivar_size_read(struct efivar_entry *entry, char *buf) | |||
507 | { | 438 | { |
508 | struct efi_variable *var = &entry->var; | 439 | struct efi_variable *var = &entry->var; |
509 | char *str = buf; | 440 | char *str = buf; |
510 | efi_status_t status; | ||
511 | 441 | ||
512 | if (!entry || !buf) | 442 | if (!entry || !buf) |
513 | return -EINVAL; | 443 | return -EINVAL; |
514 | 444 | ||
515 | status = get_var_data(__efivars, var); | 445 | var->DataSize = 1024; |
516 | if (status != EFI_SUCCESS) | 446 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) |
517 | return -EIO; | 447 | return -EIO; |
518 | 448 | ||
519 | str += sprintf(str, "0x%lx\n", var->DataSize); | 449 | str += sprintf(str, "0x%lx\n", var->DataSize); |
@@ -524,13 +454,12 @@ static ssize_t | |||
524 | efivar_data_read(struct efivar_entry *entry, char *buf) | 454 | efivar_data_read(struct efivar_entry *entry, char *buf) |
525 | { | 455 | { |
526 | struct efi_variable *var = &entry->var; | 456 | struct efi_variable *var = &entry->var; |
527 | efi_status_t status; | ||
528 | 457 | ||
529 | if (!entry || !buf) | 458 | if (!entry || !buf) |
530 | return -EINVAL; | 459 | return -EINVAL; |
531 | 460 | ||
532 | status = get_var_data(__efivars, var); | 461 | var->DataSize = 1024; |
533 | if (status != EFI_SUCCESS) | 462 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) |
534 | return -EIO; | 463 | return -EIO; |
535 | 464 | ||
536 | memcpy(buf, var->Data, var->DataSize); | 465 | memcpy(buf, var->Data, var->DataSize); |
@@ -544,8 +473,7 @@ static ssize_t | |||
544 | efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | 473 | efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) |
545 | { | 474 | { |
546 | struct efi_variable *new_var, *var = &entry->var; | 475 | struct efi_variable *new_var, *var = &entry->var; |
547 | struct efivars *efivars = __efivars; | 476 | int err; |
548 | efi_status_t status = EFI_NOT_FOUND; | ||
549 | 477 | ||
550 | if (count != sizeof(struct efi_variable)) | 478 | if (count != sizeof(struct efi_variable)) |
551 | return -EINVAL; | 479 | return -EINVAL; |
@@ -567,32 +495,20 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | |||
567 | } | 495 | } |
568 | 496 | ||
569 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | 497 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || |
570 | validate_var(new_var, new_var->Data, new_var->DataSize) == false) { | 498 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { |
571 | printk(KERN_ERR "efivars: Malformed variable content\n"); | 499 | printk(KERN_ERR "efivars: Malformed variable content\n"); |
572 | return -EINVAL; | 500 | return -EINVAL; |
573 | } | 501 | } |
574 | 502 | ||
575 | spin_lock_irq(&efivars->lock); | 503 | memcpy(&entry->var, new_var, count); |
576 | |||
577 | status = check_var_size_locked(efivars, new_var->Attributes, | ||
578 | new_var->DataSize + utf16_strsize(new_var->VariableName, 1024)); | ||
579 | |||
580 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) | ||
581 | status = efivars->ops->set_variable(new_var->VariableName, | ||
582 | &new_var->VendorGuid, | ||
583 | new_var->Attributes, | ||
584 | new_var->DataSize, | ||
585 | new_var->Data); | ||
586 | |||
587 | spin_unlock_irq(&efivars->lock); | ||
588 | 504 | ||
589 | if (status != EFI_SUCCESS) { | 505 | err = efivar_entry_set(entry, new_var->Attributes, |
590 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | 506 | new_var->DataSize, new_var->Data, false); |
591 | status); | 507 | if (err) { |
508 | printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); | ||
592 | return -EIO; | 509 | return -EIO; |
593 | } | 510 | } |
594 | 511 | ||
595 | memcpy(&entry->var, new_var, count); | ||
596 | return count; | 512 | return count; |
597 | } | 513 | } |
598 | 514 | ||
@@ -600,16 +516,17 @@ static ssize_t | |||
600 | efivar_show_raw(struct efivar_entry *entry, char *buf) | 516 | efivar_show_raw(struct efivar_entry *entry, char *buf) |
601 | { | 517 | { |
602 | struct efi_variable *var = &entry->var; | 518 | struct efi_variable *var = &entry->var; |
603 | efi_status_t status; | ||
604 | 519 | ||
605 | if (!entry || !buf) | 520 | if (!entry || !buf) |
606 | return 0; | 521 | return 0; |
607 | 522 | ||
608 | status = get_var_data(__efivars, var); | 523 | var->DataSize = 1024; |
609 | if (status != EFI_SUCCESS) | 524 | if (efivar_entry_get(entry, &entry->var.Attributes, |
525 | &entry->var.DataSize, entry->var.Data)) | ||
610 | return -EIO; | 526 | return -EIO; |
611 | 527 | ||
612 | memcpy(buf, var, sizeof(*var)); | 528 | memcpy(buf, var, sizeof(*var)); |
529 | |||
613 | return sizeof(*var); | 530 | return sizeof(*var); |
614 | } | 531 | } |
615 | 532 | ||
@@ -698,6 +615,9 @@ static int efi_status_to_err(efi_status_t status) | |||
698 | int err; | 615 | int err; |
699 | 616 | ||
700 | switch (status) { | 617 | switch (status) { |
618 | case EFI_SUCCESS: | ||
619 | err = 0; | ||
620 | break; | ||
701 | case EFI_INVALID_PARAMETER: | 621 | case EFI_INVALID_PARAMETER: |
702 | err = -EINVAL; | 622 | err = -EINVAL; |
703 | break; | 623 | break; |
@@ -714,7 +634,7 @@ static int efi_status_to_err(efi_status_t status) | |||
714 | err = -EACCES; | 634 | err = -EACCES; |
715 | break; | 635 | break; |
716 | case EFI_NOT_FOUND: | 636 | case EFI_NOT_FOUND: |
717 | err = -EIO; | 637 | err = -ENOENT; |
718 | break; | 638 | break; |
719 | default: | 639 | default: |
720 | err = -EINVAL; | 640 | err = -EINVAL; |
@@ -727,14 +647,12 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
727 | const char __user *userbuf, size_t count, loff_t *ppos) | 647 | const char __user *userbuf, size_t count, loff_t *ppos) |
728 | { | 648 | { |
729 | struct efivar_entry *var = file->private_data; | 649 | struct efivar_entry *var = file->private_data; |
730 | struct efivars *efivars = __efivars; | ||
731 | efi_status_t status; | ||
732 | void *data; | 650 | void *data; |
733 | u32 attributes; | 651 | u32 attributes; |
734 | struct inode *inode = file->f_mapping->host; | 652 | struct inode *inode = file->f_mapping->host; |
735 | unsigned long datasize = count - sizeof(attributes); | 653 | unsigned long datasize = count - sizeof(attributes); |
736 | unsigned long newdatasize, varsize; | ||
737 | ssize_t bytes = 0; | 654 | ssize_t bytes = 0; |
655 | bool set = false; | ||
738 | 656 | ||
739 | if (count < sizeof(attributes)) | 657 | if (count < sizeof(attributes)) |
740 | return -EINVAL; | 658 | return -EINVAL; |
@@ -745,23 +663,6 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
745 | if (attributes & ~(EFI_VARIABLE_MASK)) | 663 | if (attributes & ~(EFI_VARIABLE_MASK)) |
746 | return -EINVAL; | 664 | return -EINVAL; |
747 | 665 | ||
748 | /* | ||
749 | * Ensure that the user can't allocate arbitrarily large | ||
750 | * amounts of memory. Pick a default size of 64K if | ||
751 | * QueryVariableInfo() isn't supported by the firmware. | ||
752 | */ | ||
753 | |||
754 | varsize = datasize + utf16_strsize(var->var.VariableName, 1024); | ||
755 | status = check_var_size(efivars, attributes, varsize); | ||
756 | |||
757 | if (status != EFI_SUCCESS) { | ||
758 | if (status != EFI_UNSUPPORTED) | ||
759 | return efi_status_to_err(status); | ||
760 | |||
761 | if (datasize > 65536) | ||
762 | return -ENOSPC; | ||
763 | } | ||
764 | |||
765 | data = kmalloc(datasize, GFP_KERNEL); | 666 | data = kmalloc(datasize, GFP_KERNEL); |
766 | if (!data) | 667 | if (!data) |
767 | return -ENOMEM; | 668 | return -ENOMEM; |
@@ -771,76 +672,24 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
771 | goto out; | 672 | goto out; |
772 | } | 673 | } |
773 | 674 | ||
774 | if (validate_var(&var->var, data, datasize) == false) { | 675 | bytes = efivar_entry_set_get_size(var, attributes, &datasize, |
775 | bytes = -EINVAL; | 676 | data, &set); |
677 | if (!set && bytes) | ||
776 | goto out; | 678 | goto out; |
777 | } | ||
778 | |||
779 | /* | ||
780 | * The lock here protects the get_variable call, the conditional | ||
781 | * set_variable call, and removal of the variable from the efivars | ||
782 | * list (in the case of an authenticated delete). | ||
783 | */ | ||
784 | spin_lock_irq(&efivars->lock); | ||
785 | |||
786 | /* | ||
787 | * Ensure that the available space hasn't shrunk below the safe level | ||
788 | */ | ||
789 | |||
790 | status = check_var_size_locked(efivars, attributes, varsize); | ||
791 | |||
792 | if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) { | ||
793 | spin_unlock_irq(&efivars->lock); | ||
794 | kfree(data); | ||
795 | 679 | ||
796 | return efi_status_to_err(status); | 680 | if (!bytes) { |
797 | } | ||
798 | |||
799 | status = efivars->ops->set_variable(var->var.VariableName, | ||
800 | &var->var.VendorGuid, | ||
801 | attributes, datasize, | ||
802 | data); | ||
803 | |||
804 | if (status != EFI_SUCCESS) { | ||
805 | spin_unlock_irq(&efivars->lock); | ||
806 | kfree(data); | ||
807 | |||
808 | return efi_status_to_err(status); | ||
809 | } | ||
810 | |||
811 | bytes = count; | ||
812 | |||
813 | /* | ||
814 | * Writing to the variable may have caused a change in size (which | ||
815 | * could either be an append or an overwrite), or the variable to be | ||
816 | * deleted. Perform a GetVariable() so we can tell what actually | ||
817 | * happened. | ||
818 | */ | ||
819 | newdatasize = 0; | ||
820 | status = efivars->ops->get_variable(var->var.VariableName, | ||
821 | &var->var.VendorGuid, | ||
822 | NULL, &newdatasize, | ||
823 | NULL); | ||
824 | |||
825 | if (status == EFI_BUFFER_TOO_SMALL) { | ||
826 | spin_unlock_irq(&efivars->lock); | ||
827 | mutex_lock(&inode->i_mutex); | 681 | mutex_lock(&inode->i_mutex); |
828 | i_size_write(inode, newdatasize + sizeof(attributes)); | 682 | i_size_write(inode, datasize + sizeof(attributes)); |
829 | mutex_unlock(&inode->i_mutex); | 683 | mutex_unlock(&inode->i_mutex); |
830 | 684 | } else if (bytes == -ENOENT) { | |
831 | } else if (status == EFI_NOT_FOUND) { | ||
832 | list_del(&var->list); | ||
833 | spin_unlock_irq(&efivars->lock); | ||
834 | efivar_unregister(var); | ||
835 | drop_nlink(inode); | 685 | drop_nlink(inode); |
836 | d_delete(file->f_dentry); | 686 | d_delete(file->f_dentry); |
837 | dput(file->f_dentry); | 687 | dput(file->f_dentry); |
838 | 688 | } else | |
839 | } else { | ||
840 | spin_unlock_irq(&efivars->lock); | ||
841 | pr_warn("efivarfs: inconsistent EFI variable implementation? " | 689 | pr_warn("efivarfs: inconsistent EFI variable implementation? " |
842 | "status = %lx\n", status); | 690 | "status=%zu\n", bytes); |
843 | } | 691 | |
692 | bytes = count; | ||
844 | 693 | ||
845 | out: | 694 | out: |
846 | kfree(data); | 695 | kfree(data); |
@@ -852,38 +701,25 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, | |||
852 | size_t count, loff_t *ppos) | 701 | size_t count, loff_t *ppos) |
853 | { | 702 | { |
854 | struct efivar_entry *var = file->private_data; | 703 | struct efivar_entry *var = file->private_data; |
855 | struct efivars *efivars = __efivars; | ||
856 | efi_status_t status; | ||
857 | unsigned long datasize = 0; | 704 | unsigned long datasize = 0; |
858 | u32 attributes; | 705 | u32 attributes; |
859 | void *data; | 706 | void *data; |
860 | ssize_t size = 0; | 707 | ssize_t size = 0; |
708 | int err; | ||
861 | 709 | ||
862 | spin_lock_irq(&efivars->lock); | 710 | err = efivar_entry_size(var, &datasize); |
863 | status = efivars->ops->get_variable(var->var.VariableName, | 711 | if (err) |
864 | &var->var.VendorGuid, | 712 | return err; |
865 | &attributes, &datasize, NULL); | ||
866 | spin_unlock_irq(&efivars->lock); | ||
867 | |||
868 | if (status != EFI_BUFFER_TOO_SMALL) | ||
869 | return efi_status_to_err(status); | ||
870 | 713 | ||
871 | data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); | 714 | data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); |
872 | 715 | ||
873 | if (!data) | 716 | if (!data) |
874 | return -ENOMEM; | 717 | return -ENOMEM; |
875 | 718 | ||
876 | spin_lock_irq(&efivars->lock); | 719 | size = efivar_entry_get(var, &attributes, &datasize, |
877 | status = efivars->ops->get_variable(var->var.VariableName, | 720 | data + sizeof(attributes)); |
878 | &var->var.VendorGuid, | 721 | if (size) |
879 | &attributes, &datasize, | ||
880 | (data + sizeof(attributes))); | ||
881 | spin_unlock_irq(&efivars->lock); | ||
882 | |||
883 | if (status != EFI_SUCCESS) { | ||
884 | size = efi_status_to_err(status); | ||
885 | goto out_free; | 722 | goto out_free; |
886 | } | ||
887 | 723 | ||
888 | memcpy(data, &attributes, sizeof(attributes)); | 724 | memcpy(data, &attributes, sizeof(attributes)); |
889 | size = simple_read_from_buffer(userbuf, count, ppos, | 725 | size = simple_read_from_buffer(userbuf, count, ppos, |
@@ -947,17 +783,17 @@ static struct inode *efivarfs_get_inode(struct super_block *sb, | |||
947 | */ | 783 | */ |
948 | static bool efivarfs_valid_name(const char *str, int len) | 784 | static bool efivarfs_valid_name(const char *str, int len) |
949 | { | 785 | { |
950 | static const char dashes[GUID_LEN] = { | 786 | static const char dashes[EFI_VARIABLE_GUID_LEN] = { |
951 | [8] = 1, [13] = 1, [18] = 1, [23] = 1 | 787 | [8] = 1, [13] = 1, [18] = 1, [23] = 1 |
952 | }; | 788 | }; |
953 | const char *s = str + len - GUID_LEN; | 789 | const char *s = str + len - EFI_VARIABLE_GUID_LEN; |
954 | int i; | 790 | int i; |
955 | 791 | ||
956 | /* | 792 | /* |
957 | * We need a GUID, plus at least one letter for the variable name, | 793 | * We need a GUID, plus at least one letter for the variable name, |
958 | * plus the '-' separator | 794 | * plus the '-' separator |
959 | */ | 795 | */ |
960 | if (len < GUID_LEN + 2) | 796 | if (len < EFI_VARIABLE_GUID_LEN + 2) |
961 | return false; | 797 | return false; |
962 | 798 | ||
963 | /* GUID must be preceded by a '-' */ | 799 | /* GUID must be preceded by a '-' */ |
@@ -969,7 +805,7 @@ static bool efivarfs_valid_name(const char *str, int len) | |||
969 | * | 805 | * |
970 | * 12345678-1234-1234-1234-123456789abc | 806 | * 12345678-1234-1234-1234-123456789abc |
971 | */ | 807 | */ |
972 | for (i = 0; i < GUID_LEN; i++) { | 808 | for (i = 0; i < EFI_VARIABLE_GUID_LEN; i++) { |
973 | if (dashes[i]) { | 809 | if (dashes[i]) { |
974 | if (*s++ != '-') | 810 | if (*s++ != '-') |
975 | return false; | 811 | return false; |
@@ -1006,7 +842,6 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, | |||
1006 | umode_t mode, bool excl) | 842 | umode_t mode, bool excl) |
1007 | { | 843 | { |
1008 | struct inode *inode; | 844 | struct inode *inode; |
1009 | struct efivars *efivars = __efivars; | ||
1010 | struct efivar_entry *var; | 845 | struct efivar_entry *var; |
1011 | int namelen, i = 0, err = 0; | 846 | int namelen, i = 0, err = 0; |
1012 | 847 | ||
@@ -1024,7 +859,7 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, | |||
1024 | } | 859 | } |
1025 | 860 | ||
1026 | /* length of the variable name itself: remove GUID and separator */ | 861 | /* length of the variable name itself: remove GUID and separator */ |
1027 | namelen = dentry->d_name.len - GUID_LEN - 1; | 862 | namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; |
1028 | 863 | ||
1029 | efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, | 864 | efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, |
1030 | &var->var.VendorGuid); | 865 | &var->var.VendorGuid); |
@@ -1035,17 +870,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, | |||
1035 | var->var.VariableName[i] = '\0'; | 870 | var->var.VariableName[i] = '\0'; |
1036 | 871 | ||
1037 | inode->i_private = var; | 872 | inode->i_private = var; |
1038 | var->kobj.kset = efivars->kset; | ||
1039 | 873 | ||
1040 | err = kobject_init_and_add(&var->kobj, &efivar_ktype, NULL, "%s", | 874 | efivar_entry_add(var, &efivarfs_list); |
1041 | dentry->d_name.name); | ||
1042 | if (err) | ||
1043 | goto out; | ||
1044 | |||
1045 | kobject_uevent(&var->kobj, KOBJ_ADD); | ||
1046 | spin_lock_irq(&efivars->lock); | ||
1047 | list_add(&var->list, &efivars->list); | ||
1048 | spin_unlock_irq(&efivars->lock); | ||
1049 | d_instantiate(dentry, inode); | 875 | d_instantiate(dentry, inode); |
1050 | dget(dentry); | 876 | dget(dentry); |
1051 | out: | 877 | out: |
@@ -1059,26 +885,13 @@ out: | |||
1059 | static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) | 885 | static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) |
1060 | { | 886 | { |
1061 | struct efivar_entry *var = dentry->d_inode->i_private; | 887 | struct efivar_entry *var = dentry->d_inode->i_private; |
1062 | struct efivars *efivars = __efivars; | ||
1063 | efi_status_t status; | ||
1064 | |||
1065 | spin_lock_irq(&efivars->lock); | ||
1066 | 888 | ||
1067 | status = efivars->ops->set_variable(var->var.VariableName, | 889 | if (efivar_entry_delete(var)) |
1068 | &var->var.VendorGuid, | 890 | return -EINVAL; |
1069 | 0, 0, NULL); | ||
1070 | |||
1071 | if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) { | ||
1072 | list_del(&var->list); | ||
1073 | spin_unlock_irq(&efivars->lock); | ||
1074 | efivar_unregister(var); | ||
1075 | drop_nlink(dentry->d_inode); | ||
1076 | dput(dentry); | ||
1077 | return 0; | ||
1078 | } | ||
1079 | 891 | ||
1080 | spin_unlock_irq(&efivars->lock); | 892 | drop_nlink(dentry->d_inode); |
1081 | return -EINVAL; | 893 | dput(dentry); |
894 | return 0; | ||
1082 | }; | 895 | }; |
1083 | 896 | ||
1084 | /* | 897 | /* |
@@ -1097,7 +910,7 @@ static int efivarfs_d_compare(const struct dentry *parent, const struct inode *p | |||
1097 | unsigned int len, const char *str, | 910 | unsigned int len, const char *str, |
1098 | const struct qstr *name) | 911 | const struct qstr *name) |
1099 | { | 912 | { |
1100 | int guid = len - GUID_LEN; | 913 | int guid = len - EFI_VARIABLE_GUID_LEN; |
1101 | 914 | ||
1102 | if (name->len != len) | 915 | if (name->len != len) |
1103 | return 1; | 916 | return 1; |
@@ -1107,7 +920,7 @@ static int efivarfs_d_compare(const struct dentry *parent, const struct inode *p | |||
1107 | return 1; | 920 | return 1; |
1108 | 921 | ||
1109 | /* Case-insensitive compare for the GUID */ | 922 | /* Case-insensitive compare for the GUID */ |
1110 | return strncasecmp(name->name + guid, str + guid, GUID_LEN); | 923 | return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN); |
1111 | } | 924 | } |
1112 | 925 | ||
1113 | static int efivarfs_d_hash(const struct dentry *dentry, | 926 | static int efivarfs_d_hash(const struct dentry *dentry, |
@@ -1120,7 +933,7 @@ static int efivarfs_d_hash(const struct dentry *dentry, | |||
1120 | if (!efivarfs_valid_name(s, len)) | 933 | if (!efivarfs_valid_name(s, len)) |
1121 | return -EINVAL; | 934 | return -EINVAL; |
1122 | 935 | ||
1123 | while (len-- > GUID_LEN) | 936 | while (len-- > EFI_VARIABLE_GUID_LEN) |
1124 | hash = partial_name_hash(*s++, hash); | 937 | hash = partial_name_hash(*s++, hash); |
1125 | 938 | ||
1126 | /* GUID is case-insensitive. */ | 939 | /* GUID is case-insensitive. */ |
@@ -1166,15 +979,87 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) | |||
1166 | return ERR_PTR(-ENOMEM); | 979 | return ERR_PTR(-ENOMEM); |
1167 | } | 980 | } |
1168 | 981 | ||
1169 | static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | 982 | static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, |
983 | unsigned long name_size, void *data) | ||
1170 | { | 984 | { |
985 | struct super_block *sb = (struct super_block *)data; | ||
986 | struct efivar_entry *entry; | ||
1171 | struct inode *inode = NULL; | 987 | struct inode *inode = NULL; |
1172 | struct dentry *root; | 988 | struct dentry *dentry, *root = sb->s_root; |
1173 | struct efivar_entry *entry, *n; | 989 | unsigned long size = 0; |
1174 | struct efivars *efivars = __efivars; | ||
1175 | char *name; | 990 | char *name; |
991 | int len, i; | ||
1176 | int err = -ENOMEM; | 992 | int err = -ENOMEM; |
1177 | 993 | ||
994 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
995 | if (!entry) | ||
996 | return err; | ||
997 | |||
998 | memcpy(entry->var.VariableName, name16, name_size); | ||
999 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
1000 | |||
1001 | len = utf16_strlen(entry->var.VariableName); | ||
1002 | |||
1003 | /* name, plus '-', plus GUID, plus NUL*/ | ||
1004 | name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); | ||
1005 | if (!name) | ||
1006 | goto fail; | ||
1007 | |||
1008 | for (i = 0; i < len; i++) | ||
1009 | name[i] = entry->var.VariableName[i] & 0xFF; | ||
1010 | |||
1011 | name[len] = '-'; | ||
1012 | |||
1013 | efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); | ||
1014 | |||
1015 | name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; | ||
1016 | |||
1017 | inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0); | ||
1018 | if (!inode) | ||
1019 | goto fail_name; | ||
1020 | |||
1021 | dentry = efivarfs_alloc_dentry(root, name); | ||
1022 | if (IS_ERR(dentry)) { | ||
1023 | err = PTR_ERR(dentry); | ||
1024 | goto fail_inode; | ||
1025 | } | ||
1026 | |||
1027 | /* copied by the above to local storage in the dentry. */ | ||
1028 | kfree(name); | ||
1029 | |||
1030 | efivar_entry_size(entry, &size); | ||
1031 | efivar_entry_add(entry, &efivarfs_list); | ||
1032 | |||
1033 | mutex_lock(&inode->i_mutex); | ||
1034 | inode->i_private = entry; | ||
1035 | i_size_write(inode, size + sizeof(entry->var.Attributes)); | ||
1036 | mutex_unlock(&inode->i_mutex); | ||
1037 | d_add(dentry, inode); | ||
1038 | |||
1039 | return 0; | ||
1040 | |||
1041 | fail_inode: | ||
1042 | iput(inode); | ||
1043 | fail_name: | ||
1044 | kfree(name); | ||
1045 | fail: | ||
1046 | kfree(entry); | ||
1047 | return err; | ||
1048 | } | ||
1049 | |||
1050 | static int efivarfs_destroy(struct efivar_entry *entry, void *data) | ||
1051 | { | ||
1052 | efivar_entry_remove(entry); | ||
1053 | kfree(entry); | ||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | ||
1058 | { | ||
1059 | struct inode *inode = NULL; | ||
1060 | struct dentry *root; | ||
1061 | int err; | ||
1062 | |||
1178 | efivarfs_sb = sb; | 1063 | efivarfs_sb = sb; |
1179 | 1064 | ||
1180 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 1065 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
@@ -1195,65 +1080,13 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | |||
1195 | if (!root) | 1080 | if (!root) |
1196 | return -ENOMEM; | 1081 | return -ENOMEM; |
1197 | 1082 | ||
1198 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | 1083 | INIT_LIST_HEAD(&efivarfs_list); |
1199 | struct dentry *dentry, *root = efivarfs_sb->s_root; | ||
1200 | unsigned long size = 0; | ||
1201 | int len, i; | ||
1202 | |||
1203 | inode = NULL; | ||
1204 | |||
1205 | len = utf16_strlen(entry->var.VariableName); | ||
1206 | |||
1207 | /* name, plus '-', plus GUID, plus NUL*/ | ||
1208 | name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC); | ||
1209 | if (!name) | ||
1210 | goto fail; | ||
1211 | 1084 | ||
1212 | for (i = 0; i < len; i++) | 1085 | err = efivar_init(efivarfs_callback, (void *)sb, false, |
1213 | name[i] = entry->var.VariableName[i] & 0xFF; | 1086 | true, &efivarfs_list); |
1214 | 1087 | if (err) | |
1215 | name[len] = '-'; | 1088 | __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL); |
1216 | |||
1217 | efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); | ||
1218 | |||
1219 | name[len+GUID_LEN+1] = '\0'; | ||
1220 | |||
1221 | inode = efivarfs_get_inode(efivarfs_sb, root->d_inode, | ||
1222 | S_IFREG | 0644, 0); | ||
1223 | if (!inode) | ||
1224 | goto fail_name; | ||
1225 | |||
1226 | dentry = efivarfs_alloc_dentry(root, name); | ||
1227 | if (IS_ERR(dentry)) { | ||
1228 | err = PTR_ERR(dentry); | ||
1229 | goto fail_inode; | ||
1230 | } | ||
1231 | |||
1232 | /* copied by the above to local storage in the dentry. */ | ||
1233 | kfree(name); | ||
1234 | |||
1235 | spin_lock_irq(&efivars->lock); | ||
1236 | efivars->ops->get_variable(entry->var.VariableName, | ||
1237 | &entry->var.VendorGuid, | ||
1238 | &entry->var.Attributes, | ||
1239 | &size, | ||
1240 | NULL); | ||
1241 | spin_unlock_irq(&efivars->lock); | ||
1242 | |||
1243 | mutex_lock(&inode->i_mutex); | ||
1244 | inode->i_private = entry; | ||
1245 | i_size_write(inode, size + sizeof(entry->var.Attributes)); | ||
1246 | mutex_unlock(&inode->i_mutex); | ||
1247 | d_add(dentry, inode); | ||
1248 | } | ||
1249 | |||
1250 | return 0; | ||
1251 | 1089 | ||
1252 | fail_inode: | ||
1253 | iput(inode); | ||
1254 | fail_name: | ||
1255 | kfree(name); | ||
1256 | fail: | ||
1257 | return err; | 1090 | return err; |
1258 | } | 1091 | } |
1259 | 1092 | ||
@@ -1267,6 +1100,9 @@ static void efivarfs_kill_sb(struct super_block *sb) | |||
1267 | { | 1100 | { |
1268 | kill_litter_super(sb); | 1101 | kill_litter_super(sb); |
1269 | efivarfs_sb = NULL; | 1102 | efivarfs_sb = NULL; |
1103 | |||
1104 | /* Remove all entries and destroy */ | ||
1105 | __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL); | ||
1270 | } | 1106 | } |
1271 | 1107 | ||
1272 | static struct file_system_type efivarfs_type = { | 1108 | static struct file_system_type efivarfs_type = { |
@@ -1298,80 +1134,84 @@ static const struct inode_operations efivarfs_dir_inode_operations = { | |||
1298 | 1134 | ||
1299 | static int efi_pstore_open(struct pstore_info *psi) | 1135 | static int efi_pstore_open(struct pstore_info *psi) |
1300 | { | 1136 | { |
1301 | struct efivars *efivars = __efivars; | 1137 | efivar_entry_iter_begin(); |
1302 | 1138 | psi->data = NULL; | |
1303 | spin_lock_irq(&efivars->lock); | ||
1304 | efivars->walk_entry = list_first_entry(&efivars->list, | ||
1305 | struct efivar_entry, list); | ||
1306 | return 0; | 1139 | return 0; |
1307 | } | 1140 | } |
1308 | 1141 | ||
1309 | static int efi_pstore_close(struct pstore_info *psi) | 1142 | static int efi_pstore_close(struct pstore_info *psi) |
1310 | { | 1143 | { |
1311 | struct efivars *efivars = __efivars; | 1144 | efivar_entry_iter_end(); |
1312 | 1145 | psi->data = NULL; | |
1313 | spin_unlock_irq(&efivars->lock); | ||
1314 | return 0; | 1146 | return 0; |
1315 | } | 1147 | } |
1316 | 1148 | ||
1317 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | 1149 | struct pstore_read_data { |
1318 | int *count, struct timespec *timespec, | 1150 | u64 *id; |
1319 | char **buf, struct pstore_info *psi) | 1151 | enum pstore_type_id *type; |
1152 | int *count; | ||
1153 | struct timespec *timespec; | ||
1154 | char **buf; | ||
1155 | }; | ||
1156 | |||
1157 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | ||
1320 | { | 1158 | { |
1321 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | 1159 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; |
1322 | struct efivars *efivars = __efivars; | 1160 | struct pstore_read_data *cb_data = data; |
1323 | char name[DUMP_NAME_LEN]; | 1161 | char name[DUMP_NAME_LEN]; |
1324 | int i; | 1162 | int i; |
1325 | int cnt; | 1163 | int cnt; |
1326 | unsigned int part, size; | 1164 | unsigned int part; |
1327 | unsigned long time; | 1165 | unsigned long time, size; |
1328 | |||
1329 | while (&efivars->walk_entry->list != &efivars->list) { | ||
1330 | if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid, | ||
1331 | vendor)) { | ||
1332 | for (i = 0; i < DUMP_NAME_LEN; i++) { | ||
1333 | name[i] = efivars->walk_entry->var.VariableName[i]; | ||
1334 | } | ||
1335 | if (sscanf(name, "dump-type%u-%u-%d-%lu", | ||
1336 | type, &part, &cnt, &time) == 4) { | ||
1337 | *id = part; | ||
1338 | *count = cnt; | ||
1339 | timespec->tv_sec = time; | ||
1340 | timespec->tv_nsec = 0; | ||
1341 | } else if (sscanf(name, "dump-type%u-%u-%lu", | ||
1342 | type, &part, &time) == 3) { | ||
1343 | /* | ||
1344 | * Check if an old format, | ||
1345 | * which doesn't support holding | ||
1346 | * multiple logs, remains. | ||
1347 | */ | ||
1348 | *id = part; | ||
1349 | *count = 0; | ||
1350 | timespec->tv_sec = time; | ||
1351 | timespec->tv_nsec = 0; | ||
1352 | } else { | ||
1353 | efivars->walk_entry = list_entry( | ||
1354 | efivars->walk_entry->list.next, | ||
1355 | struct efivar_entry, list); | ||
1356 | continue; | ||
1357 | } | ||
1358 | 1166 | ||
1359 | get_var_data_locked(efivars, &efivars->walk_entry->var); | 1167 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) |
1360 | size = efivars->walk_entry->var.DataSize; | 1168 | return 0; |
1361 | *buf = kmalloc(size, GFP_KERNEL); | 1169 | |
1362 | if (*buf == NULL) | 1170 | for (i = 0; i < DUMP_NAME_LEN; i++) |
1363 | return -ENOMEM; | 1171 | name[i] = entry->var.VariableName[i]; |
1364 | memcpy(*buf, efivars->walk_entry->var.Data, | 1172 | |
1365 | size); | 1173 | if (sscanf(name, "dump-type%u-%u-%d-%lu", |
1366 | efivars->walk_entry = list_entry( | 1174 | cb_data->type, &part, &cnt, &time) == 4) { |
1367 | efivars->walk_entry->list.next, | 1175 | *cb_data->id = part; |
1368 | struct efivar_entry, list); | 1176 | *cb_data->count = cnt; |
1369 | return size; | 1177 | cb_data->timespec->tv_sec = time; |
1370 | } | 1178 | cb_data->timespec->tv_nsec = 0; |
1371 | efivars->walk_entry = list_entry(efivars->walk_entry->list.next, | 1179 | } else if (sscanf(name, "dump-type%u-%u-%lu", |
1372 | struct efivar_entry, list); | 1180 | cb_data->type, &part, &time) == 3) { |
1373 | } | 1181 | /* |
1374 | return 0; | 1182 | * Check if an old format, |
1183 | * which doesn't support holding | ||
1184 | * multiple logs, remains. | ||
1185 | */ | ||
1186 | *cb_data->id = part; | ||
1187 | *cb_data->count = 0; | ||
1188 | cb_data->timespec->tv_sec = time; | ||
1189 | cb_data->timespec->tv_nsec = 0; | ||
1190 | } else | ||
1191 | return 0; | ||
1192 | |||
1193 | __efivar_entry_size(entry, &size); | ||
1194 | *cb_data->buf = kmalloc(size, GFP_KERNEL); | ||
1195 | if (*cb_data->buf == NULL) | ||
1196 | return -ENOMEM; | ||
1197 | memcpy(*cb_data->buf, entry->var.Data, size); | ||
1198 | return size; | ||
1199 | } | ||
1200 | |||
1201 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | ||
1202 | int *count, struct timespec *timespec, | ||
1203 | char **buf, struct pstore_info *psi) | ||
1204 | { | ||
1205 | struct pstore_read_data data; | ||
1206 | |||
1207 | data.id = id; | ||
1208 | data.type = type; | ||
1209 | data.count = count; | ||
1210 | data.timespec = timespec; | ||
1211 | data.buf = buf; | ||
1212 | |||
1213 | return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, | ||
1214 | (struct efivar_entry **)&psi->data); | ||
1375 | } | 1215 | } |
1376 | 1216 | ||
1377 | static int efi_pstore_write(enum pstore_type_id type, | 1217 | static int efi_pstore_write(enum pstore_type_id type, |
@@ -1382,36 +1222,7 @@ static int efi_pstore_write(enum pstore_type_id type, | |||
1382 | char name[DUMP_NAME_LEN]; | 1222 | char name[DUMP_NAME_LEN]; |
1383 | efi_char16_t efi_name[DUMP_NAME_LEN]; | 1223 | efi_char16_t efi_name[DUMP_NAME_LEN]; |
1384 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | 1224 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; |
1385 | struct efivars *efivars = __efivars; | ||
1386 | int i, ret = 0; | 1225 | int i, ret = 0; |
1387 | efi_status_t status = EFI_NOT_FOUND; | ||
1388 | unsigned long flags; | ||
1389 | |||
1390 | if (pstore_cannot_block_path(reason)) { | ||
1391 | /* | ||
1392 | * If the lock is taken by another cpu in non-blocking path, | ||
1393 | * this driver returns without entering firmware to avoid | ||
1394 | * hanging up. | ||
1395 | */ | ||
1396 | if (!spin_trylock_irqsave(&efivars->lock, flags)) | ||
1397 | return -EBUSY; | ||
1398 | } else | ||
1399 | spin_lock_irqsave(&efivars->lock, flags); | ||
1400 | |||
1401 | /* | ||
1402 | * Check if there is a space enough to log. | ||
1403 | * size: a size of logging data | ||
1404 | * DUMP_NAME_LEN * 2: a maximum size of variable name | ||
1405 | */ | ||
1406 | |||
1407 | status = check_var_size_locked(efivars, PSTORE_EFI_ATTRIBUTES, | ||
1408 | size + DUMP_NAME_LEN * 2); | ||
1409 | |||
1410 | if (status) { | ||
1411 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
1412 | *id = part; | ||
1413 | return -ENOSPC; | ||
1414 | } | ||
1415 | 1226 | ||
1416 | sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, | 1227 | sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, |
1417 | get_seconds()); | 1228 | get_seconds()); |
@@ -1419,10 +1230,9 @@ static int efi_pstore_write(enum pstore_type_id type, | |||
1419 | for (i = 0; i < DUMP_NAME_LEN; i++) | 1230 | for (i = 0; i < DUMP_NAME_LEN; i++) |
1420 | efi_name[i] = name[i]; | 1231 | efi_name[i] = name[i]; |
1421 | 1232 | ||
1422 | efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES, | 1233 | ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, |
1423 | size, psi->buf); | 1234 | !pstore_cannot_block_path(reason), |
1424 | 1235 | size, psi->buf); | |
1425 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
1426 | 1236 | ||
1427 | if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled) | 1237 | if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled) |
1428 | schedule_work(&efivar_work); | 1238 | schedule_work(&efivar_work); |
@@ -1431,69 +1241,79 @@ static int efi_pstore_write(enum pstore_type_id type, | |||
1431 | return ret; | 1241 | return ret; |
1432 | }; | 1242 | }; |
1433 | 1243 | ||
1434 | static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | 1244 | struct pstore_erase_data { |
1435 | struct timespec time, struct pstore_info *psi) | 1245 | u64 id; |
1246 | enum pstore_type_id type; | ||
1247 | int count; | ||
1248 | struct timespec time; | ||
1249 | efi_char16_t *name; | ||
1250 | }; | ||
1251 | |||
1252 | /* | ||
1253 | * Clean up an entry with the same name | ||
1254 | */ | ||
1255 | static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) | ||
1436 | { | 1256 | { |
1437 | char name[DUMP_NAME_LEN]; | 1257 | struct pstore_erase_data *ed = data; |
1438 | efi_char16_t efi_name[DUMP_NAME_LEN]; | ||
1439 | char name_old[DUMP_NAME_LEN]; | ||
1440 | efi_char16_t efi_name_old[DUMP_NAME_LEN]; | ||
1441 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | 1258 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; |
1442 | struct efivars *efivars = __efivars; | 1259 | efi_char16_t efi_name_old[DUMP_NAME_LEN]; |
1443 | struct efivar_entry *entry, *found = NULL; | 1260 | efi_char16_t *efi_name = ed->name; |
1261 | unsigned long utf16_len = utf16_strlen(ed->name); | ||
1262 | char name_old[DUMP_NAME_LEN]; | ||
1444 | int i; | 1263 | int i; |
1445 | 1264 | ||
1446 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, | 1265 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) |
1447 | time.tv_sec); | 1266 | return 0; |
1448 | |||
1449 | spin_lock_irq(&efivars->lock); | ||
1450 | 1267 | ||
1451 | for (i = 0; i < DUMP_NAME_LEN; i++) | 1268 | if (utf16_strncmp(entry->var.VariableName, |
1452 | efi_name[i] = name[i]; | 1269 | efi_name, (size_t)utf16_len)) { |
1270 | /* | ||
1271 | * Check if an old format, which doesn't support | ||
1272 | * holding multiple logs, remains. | ||
1273 | */ | ||
1274 | sprintf(name_old, "dump-type%u-%u-%lu", ed->type, | ||
1275 | (unsigned int)ed->id, ed->time.tv_sec); | ||
1453 | 1276 | ||
1454 | /* | 1277 | for (i = 0; i < DUMP_NAME_LEN; i++) |
1455 | * Clean up an entry with the same name | 1278 | efi_name_old[i] = name_old[i]; |
1456 | */ | ||
1457 | 1279 | ||
1458 | list_for_each_entry(entry, &efivars->list, list) { | 1280 | if (utf16_strncmp(entry->var.VariableName, efi_name_old, |
1459 | get_var_data_locked(efivars, &entry->var); | 1281 | utf16_strlen(efi_name_old))) |
1282 | return 0; | ||
1283 | } | ||
1460 | 1284 | ||
1461 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) | 1285 | /* found */ |
1462 | continue; | 1286 | __efivar_entry_delete(entry); |
1463 | if (utf16_strncmp(entry->var.VariableName, efi_name, | 1287 | return 1; |
1464 | utf16_strlen(efi_name))) { | 1288 | } |
1465 | /* | ||
1466 | * Check if an old format, | ||
1467 | * which doesn't support holding | ||
1468 | * multiple logs, remains. | ||
1469 | */ | ||
1470 | sprintf(name_old, "dump-type%u-%u-%lu", type, | ||
1471 | (unsigned int)id, time.tv_sec); | ||
1472 | 1289 | ||
1473 | for (i = 0; i < DUMP_NAME_LEN; i++) | 1290 | static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, |
1474 | efi_name_old[i] = name_old[i]; | 1291 | struct timespec time, struct pstore_info *psi) |
1292 | { | ||
1293 | struct pstore_erase_data edata; | ||
1294 | struct efivar_entry *entry; | ||
1295 | char name[DUMP_NAME_LEN]; | ||
1296 | efi_char16_t efi_name[DUMP_NAME_LEN]; | ||
1297 | int found, i; | ||
1475 | 1298 | ||
1476 | if (utf16_strncmp(entry->var.VariableName, efi_name_old, | 1299 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, |
1477 | utf16_strlen(efi_name_old))) | 1300 | time.tv_sec); |
1478 | continue; | ||
1479 | } | ||
1480 | 1301 | ||
1481 | /* found */ | 1302 | for (i = 0; i < DUMP_NAME_LEN; i++) |
1482 | found = entry; | 1303 | efi_name[i] = name[i]; |
1483 | efivars->ops->set_variable(entry->var.VariableName, | ||
1484 | &entry->var.VendorGuid, | ||
1485 | PSTORE_EFI_ATTRIBUTES, | ||
1486 | 0, NULL); | ||
1487 | break; | ||
1488 | } | ||
1489 | 1304 | ||
1490 | if (found) | 1305 | edata.id = id; |
1491 | list_del(&found->list); | 1306 | edata.type = type; |
1307 | edata.count = count; | ||
1308 | edata.time = time; | ||
1309 | edata.name = efi_name; | ||
1492 | 1310 | ||
1493 | spin_unlock_irq(&efivars->lock); | 1311 | efivar_entry_iter_begin(); |
1312 | found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); | ||
1313 | efivar_entry_iter_end(); | ||
1494 | 1314 | ||
1495 | if (found) | 1315 | if (found) |
1496 | efivar_unregister(found); | 1316 | efivar_unregister(entry); |
1497 | 1317 | ||
1498 | return 0; | 1318 | return 0; |
1499 | } | 1319 | } |
@@ -1508,19 +1328,17 @@ static struct pstore_info efi_pstore_info = { | |||
1508 | .erase = efi_pstore_erase, | 1328 | .erase = efi_pstore_erase, |
1509 | }; | 1329 | }; |
1510 | 1330 | ||
1511 | static void efivar_pstore_register(struct efivars *efivars) | 1331 | static void efivar_pstore_register(void) |
1512 | { | 1332 | { |
1513 | efivars->efi_pstore_info = efi_pstore_info; | 1333 | efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); |
1514 | efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); | 1334 | if (efi_pstore_info.buf) { |
1515 | if (efivars->efi_pstore_info.buf) { | 1335 | efi_pstore_info.bufsize = 1024; |
1516 | efivars->efi_pstore_info.bufsize = 1024; | 1336 | spin_lock_init(&efi_pstore_info.buf_lock); |
1517 | efivars->efi_pstore_info.data = efivars; | 1337 | pstore_register(&efi_pstore_info); |
1518 | spin_lock_init(&efivars->efi_pstore_info.buf_lock); | ||
1519 | pstore_register(&efivars->efi_pstore_info); | ||
1520 | } | 1338 | } |
1521 | } | 1339 | } |
1522 | #else | 1340 | #else |
1523 | static void efivar_pstore_register(struct efivars *efivars) | 1341 | static void efivar_pstore_register(void) |
1524 | { | 1342 | { |
1525 | return; | 1343 | return; |
1526 | } | 1344 | } |
@@ -1531,76 +1349,41 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
1531 | char *buf, loff_t pos, size_t count) | 1349 | char *buf, loff_t pos, size_t count) |
1532 | { | 1350 | { |
1533 | struct efi_variable *new_var = (struct efi_variable *)buf; | 1351 | struct efi_variable *new_var = (struct efi_variable *)buf; |
1534 | struct efivars *efivars = __efivars; | 1352 | struct efivar_entry *new_entry; |
1535 | struct efivar_entry *search_efivar, *n; | 1353 | int err; |
1536 | unsigned long strsize1, strsize2; | ||
1537 | efi_status_t status = EFI_NOT_FOUND; | ||
1538 | int found = 0; | ||
1539 | 1354 | ||
1540 | if (!capable(CAP_SYS_ADMIN)) | 1355 | if (!capable(CAP_SYS_ADMIN)) |
1541 | return -EACCES; | 1356 | return -EACCES; |
1542 | 1357 | ||
1543 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | 1358 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || |
1544 | validate_var(new_var, new_var->Data, new_var->DataSize) == false) { | 1359 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { |
1545 | printk(KERN_ERR "efivars: Malformed variable content\n"); | 1360 | printk(KERN_ERR "efivars: Malformed variable content\n"); |
1546 | return -EINVAL; | 1361 | return -EINVAL; |
1547 | } | 1362 | } |
1548 | 1363 | ||
1549 | spin_lock_irq(&efivars->lock); | 1364 | new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); |
1550 | 1365 | if (!new_entry) | |
1551 | /* | 1366 | return -ENOMEM; |
1552 | * Does this variable already exist? | ||
1553 | */ | ||
1554 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | ||
1555 | strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | ||
1556 | strsize2 = utf16_strsize(new_var->VariableName, 1024); | ||
1557 | if (strsize1 == strsize2 && | ||
1558 | !memcmp(&(search_efivar->var.VariableName), | ||
1559 | new_var->VariableName, strsize1) && | ||
1560 | !efi_guidcmp(search_efivar->var.VendorGuid, | ||
1561 | new_var->VendorGuid)) { | ||
1562 | found = 1; | ||
1563 | break; | ||
1564 | } | ||
1565 | } | ||
1566 | if (found) { | ||
1567 | spin_unlock_irq(&efivars->lock); | ||
1568 | return -EINVAL; | ||
1569 | } | ||
1570 | 1367 | ||
1571 | status = check_var_size_locked(efivars, new_var->Attributes, | 1368 | memcpy(&new_entry->var, new_var, sizeof(*new_var)); |
1572 | new_var->DataSize + utf16_strsize(new_var->VariableName, 1024)); | ||
1573 | 1369 | ||
1574 | if (status && status != EFI_UNSUPPORTED) { | 1370 | err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, |
1575 | spin_unlock_irq(&efivars->lock); | 1371 | new_var->Data, &efivar_sysfs_list); |
1576 | return efi_status_to_err(status); | 1372 | if (err) { |
1373 | if (err == -EEXIST) | ||
1374 | err = -EINVAL; | ||
1375 | goto out; | ||
1577 | } | 1376 | } |
1578 | 1377 | ||
1579 | /* now *really* create the variable via EFI */ | 1378 | if (efivar_create_sysfs_entry(new_entry)) { |
1580 | status = efivars->ops->set_variable(new_var->VariableName, | 1379 | printk(KERN_WARNING "efivars: failed to create sysfs entry.\n"); |
1581 | &new_var->VendorGuid, | 1380 | kfree(new_entry); |
1582 | new_var->Attributes, | ||
1583 | new_var->DataSize, | ||
1584 | new_var->Data); | ||
1585 | |||
1586 | if (status != EFI_SUCCESS) { | ||
1587 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | ||
1588 | status); | ||
1589 | spin_unlock_irq(&efivars->lock); | ||
1590 | return -EIO; | ||
1591 | } | ||
1592 | spin_unlock_irq(&efivars->lock); | ||
1593 | |||
1594 | /* Create the entry in sysfs. Locking is not required here */ | ||
1595 | status = efivar_create_sysfs_entry(efivars, | ||
1596 | utf16_strsize(new_var->VariableName, | ||
1597 | 1024), | ||
1598 | new_var->VariableName, | ||
1599 | &new_var->VendorGuid); | ||
1600 | if (status) { | ||
1601 | printk(KERN_WARNING "efivars: variable created, but sysfs entry wasn't.\n"); | ||
1602 | } | 1381 | } |
1603 | return count; | 1382 | return count; |
1383 | |||
1384 | out: | ||
1385 | kfree(new_entry); | ||
1386 | return err; | ||
1604 | } | 1387 | } |
1605 | 1388 | ||
1606 | static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | 1389 | static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, |
@@ -1608,70 +1391,40 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
1608 | char *buf, loff_t pos, size_t count) | 1391 | char *buf, loff_t pos, size_t count) |
1609 | { | 1392 | { |
1610 | struct efi_variable *del_var = (struct efi_variable *)buf; | 1393 | struct efi_variable *del_var = (struct efi_variable *)buf; |
1611 | struct efivars *efivars = __efivars; | 1394 | struct efivar_entry *entry; |
1612 | struct efivar_entry *search_efivar, *n; | 1395 | int err = 0; |
1613 | unsigned long strsize1, strsize2; | ||
1614 | efi_status_t status = EFI_NOT_FOUND; | ||
1615 | int found = 0; | ||
1616 | 1396 | ||
1617 | if (!capable(CAP_SYS_ADMIN)) | 1397 | if (!capable(CAP_SYS_ADMIN)) |
1618 | return -EACCES; | 1398 | return -EACCES; |
1619 | 1399 | ||
1620 | spin_lock_irq(&efivars->lock); | 1400 | efivar_entry_iter_begin(); |
1401 | entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, | ||
1402 | &efivar_sysfs_list, true); | ||
1403 | if (!entry) | ||
1404 | err = -EINVAL; | ||
1405 | else if (__efivar_entry_delete(entry)) | ||
1406 | err = -EIO; | ||
1621 | 1407 | ||
1622 | /* | 1408 | efivar_entry_iter_end(); |
1623 | * Does this variable already exist? | ||
1624 | */ | ||
1625 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | ||
1626 | strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | ||
1627 | strsize2 = utf16_strsize(del_var->VariableName, 1024); | ||
1628 | if (strsize1 == strsize2 && | ||
1629 | !memcmp(&(search_efivar->var.VariableName), | ||
1630 | del_var->VariableName, strsize1) && | ||
1631 | !efi_guidcmp(search_efivar->var.VendorGuid, | ||
1632 | del_var->VendorGuid)) { | ||
1633 | found = 1; | ||
1634 | break; | ||
1635 | } | ||
1636 | } | ||
1637 | if (!found) { | ||
1638 | spin_unlock_irq(&efivars->lock); | ||
1639 | return -EINVAL; | ||
1640 | } | ||
1641 | /* force the Attributes/DataSize to 0 to ensure deletion */ | ||
1642 | del_var->Attributes = 0; | ||
1643 | del_var->DataSize = 0; | ||
1644 | 1409 | ||
1645 | status = efivars->ops->set_variable(del_var->VariableName, | 1410 | if (err) |
1646 | &del_var->VendorGuid, | 1411 | return err; |
1647 | del_var->Attributes, | ||
1648 | del_var->DataSize, | ||
1649 | del_var->Data); | ||
1650 | 1412 | ||
1651 | if (status != EFI_SUCCESS) { | 1413 | efivar_unregister(entry); |
1652 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | ||
1653 | status); | ||
1654 | spin_unlock_irq(&efivars->lock); | ||
1655 | return -EIO; | ||
1656 | } | ||
1657 | list_del(&search_efivar->list); | ||
1658 | /* We need to release this lock before unregistering. */ | ||
1659 | spin_unlock_irq(&efivars->lock); | ||
1660 | efivar_unregister(search_efivar); | ||
1661 | 1414 | ||
1662 | /* It's dead Jim.... */ | 1415 | /* It's dead Jim.... */ |
1663 | return count; | 1416 | return count; |
1664 | } | 1417 | } |
1665 | 1418 | ||
1666 | static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) | 1419 | static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor, |
1420 | struct list_head *head) | ||
1667 | { | 1421 | { |
1668 | struct efivar_entry *entry, *n; | 1422 | struct efivar_entry *entry, *n; |
1669 | struct efivars *efivars = __efivars; | ||
1670 | unsigned long strsize1, strsize2; | 1423 | unsigned long strsize1, strsize2; |
1671 | bool found = false; | 1424 | bool found = false; |
1672 | 1425 | ||
1673 | strsize1 = utf16_strsize(variable_name, 1024); | 1426 | strsize1 = utf16_strsize(variable_name, 1024); |
1674 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | 1427 | list_for_each_entry_safe(entry, n, head, list) { |
1675 | strsize2 = utf16_strsize(entry->var.VariableName, 1024); | 1428 | strsize2 = utf16_strsize(entry->var.VariableName, 1024); |
1676 | if (strsize1 == strsize2 && | 1429 | if (strsize1 == strsize2 && |
1677 | !memcmp(variable_name, &(entry->var.VariableName), | 1430 | !memcmp(variable_name, &(entry->var.VariableName), |
@@ -1685,6 +1438,20 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) | |||
1685 | return found; | 1438 | return found; |
1686 | } | 1439 | } |
1687 | 1440 | ||
1441 | static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor, | ||
1442 | unsigned long name_size, void *data) | ||
1443 | { | ||
1444 | struct efivar_entry *entry = data; | ||
1445 | |||
1446 | if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false)) | ||
1447 | return 0; | ||
1448 | |||
1449 | memcpy(entry->var.VariableName, name, name_size); | ||
1450 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
1451 | |||
1452 | return 1; | ||
1453 | } | ||
1454 | |||
1688 | /* | 1455 | /* |
1689 | * Returns the size of variable_name, in bytes, including the | 1456 | * Returns the size of variable_name, in bytes, including the |
1690 | * terminating NULL character, or variable_name_size if no NULL | 1457 | * terminating NULL character, or variable_name_size if no NULL |
@@ -1712,52 +1479,26 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name, | |||
1712 | 1479 | ||
1713 | static void efivar_update_sysfs_entries(struct work_struct *work) | 1480 | static void efivar_update_sysfs_entries(struct work_struct *work) |
1714 | { | 1481 | { |
1715 | struct efivars *efivars = __efivars; | 1482 | struct efivar_entry *entry; |
1716 | efi_guid_t vendor; | 1483 | int err; |
1717 | efi_char16_t *variable_name; | 1484 | |
1718 | unsigned long variable_name_size = 1024; | 1485 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
1719 | efi_status_t status = EFI_NOT_FOUND; | 1486 | if (!entry) |
1720 | bool found; | 1487 | return; |
1721 | 1488 | ||
1722 | /* Add new sysfs entries */ | 1489 | /* Add new sysfs entries */ |
1723 | while (1) { | 1490 | while (1) { |
1724 | variable_name = kzalloc(variable_name_size, GFP_KERNEL); | 1491 | memset(entry, 0, sizeof(*entry)); |
1725 | if (!variable_name) { | ||
1726 | pr_err("efivars: Memory allocation failed.\n"); | ||
1727 | return; | ||
1728 | } | ||
1729 | 1492 | ||
1730 | spin_lock_irq(&efivars->lock); | 1493 | err = efivar_init(efivar_update_sysfs_entry, entry, |
1731 | found = false; | 1494 | true, false, &efivar_sysfs_list); |
1732 | while (1) { | 1495 | if (!err) |
1733 | variable_name_size = 1024; | ||
1734 | status = efivars->ops->get_next_variable( | ||
1735 | &variable_name_size, | ||
1736 | variable_name, | ||
1737 | &vendor); | ||
1738 | if (status != EFI_SUCCESS) { | ||
1739 | break; | ||
1740 | } else { | ||
1741 | if (!variable_is_present(variable_name, | ||
1742 | &vendor)) { | ||
1743 | found = true; | ||
1744 | break; | ||
1745 | } | ||
1746 | } | ||
1747 | } | ||
1748 | spin_unlock_irq(&efivars->lock); | ||
1749 | |||
1750 | if (!found) { | ||
1751 | kfree(variable_name); | ||
1752 | break; | 1496 | break; |
1753 | } else { | 1497 | |
1754 | variable_name_size = var_name_strnsize(variable_name, | 1498 | efivar_create_sysfs_entry(entry); |
1755 | variable_name_size); | ||
1756 | efivar_create_sysfs_entry(efivars, | ||
1757 | variable_name_size, | ||
1758 | variable_name, &vendor); | ||
1759 | } | ||
1760 | } | 1499 | } |
1500 | |||
1501 | kfree(entry); | ||
1761 | } | 1502 | } |
1762 | 1503 | ||
1763 | /* | 1504 | /* |
@@ -1804,45 +1545,37 @@ static struct attribute_group efi_subsys_attr_group = { | |||
1804 | 1545 | ||
1805 | static struct kobject *efi_kobj; | 1546 | static struct kobject *efi_kobj; |
1806 | 1547 | ||
1807 | /* | 1548 | /** |
1808 | * efivar_create_sysfs_entry() | 1549 | * efivar_create_sysfs_entry - create a new entry in sysfs |
1809 | * Requires: | 1550 | * @new_var: efivar entry to create |
1810 | * variable_name_size = number of bytes required to hold | 1551 | * |
1811 | * variable_name (not counting the NULL | ||
1812 | * character at the end. | ||
1813 | * efivars->lock is not held on entry or exit. | ||
1814 | * Returns 1 on failure, 0 on success | 1552 | * Returns 1 on failure, 0 on success |
1815 | */ | 1553 | */ |
1816 | static int | 1554 | static int |
1817 | efivar_create_sysfs_entry(struct efivars *efivars, | 1555 | efivar_create_sysfs_entry(struct efivar_entry *new_var) |
1818 | unsigned long variable_name_size, | ||
1819 | efi_char16_t *variable_name, | ||
1820 | efi_guid_t *vendor_guid) | ||
1821 | { | 1556 | { |
1822 | int i, short_name_size; | 1557 | int i, short_name_size; |
1823 | char *short_name; | 1558 | char *short_name; |
1824 | struct efivar_entry *new_efivar; | 1559 | unsigned long variable_name_size; |
1560 | efi_char16_t *variable_name; | ||
1561 | |||
1562 | variable_name = new_var->var.VariableName; | ||
1563 | variable_name_size = utf16_strlen(variable_name) * sizeof(efi_char16_t); | ||
1825 | 1564 | ||
1826 | /* | 1565 | /* |
1827 | * Length of the variable bytes in ASCII, plus the '-' separator, | 1566 | * Length of the variable bytes in ASCII, plus the '-' separator, |
1828 | * plus the GUID, plus trailing NUL | 1567 | * plus the GUID, plus trailing NUL |
1829 | */ | 1568 | */ |
1830 | short_name_size = variable_name_size / sizeof(efi_char16_t) | 1569 | short_name_size = variable_name_size / sizeof(efi_char16_t) |
1831 | + 1 + GUID_LEN + 1; | 1570 | + 1 + EFI_VARIABLE_GUID_LEN + 1; |
1832 | 1571 | ||
1833 | short_name = kzalloc(short_name_size, GFP_KERNEL); | 1572 | short_name = kzalloc(short_name_size, GFP_KERNEL); |
1834 | new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); | ||
1835 | 1573 | ||
1836 | if (!short_name || !new_efivar) { | 1574 | if (!short_name) { |
1837 | kfree(short_name); | 1575 | kfree(short_name); |
1838 | kfree(new_efivar); | ||
1839 | return 1; | 1576 | return 1; |
1840 | } | 1577 | } |
1841 | 1578 | ||
1842 | memcpy(new_efivar->var.VariableName, variable_name, | ||
1843 | variable_name_size); | ||
1844 | memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t)); | ||
1845 | |||
1846 | /* Convert Unicode to normal chars (assume top bits are 0), | 1579 | /* Convert Unicode to normal chars (assume top bits are 0), |
1847 | ala UTF-8 */ | 1580 | ala UTF-8 */ |
1848 | for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { | 1581 | for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { |
@@ -1852,30 +1585,25 @@ efivar_create_sysfs_entry(struct efivars *efivars, | |||
1852 | private variables from another's. */ | 1585 | private variables from another's. */ |
1853 | 1586 | ||
1854 | *(short_name + strlen(short_name)) = '-'; | 1587 | *(short_name + strlen(short_name)) = '-'; |
1855 | efi_guid_unparse(vendor_guid, short_name + strlen(short_name)); | 1588 | efi_guid_unparse(&new_var->var.VendorGuid, |
1589 | short_name + strlen(short_name)); | ||
1856 | 1590 | ||
1857 | new_efivar->kobj.kset = efivars->kset; | 1591 | new_var->kobj.kset = efivars_kset; |
1858 | i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL, | ||
1859 | "%s", short_name); | ||
1860 | if (i) { | ||
1861 | kfree(short_name); | ||
1862 | kfree(new_efivar); | ||
1863 | return 1; | ||
1864 | } | ||
1865 | 1592 | ||
1866 | kobject_uevent(&new_efivar->kobj, KOBJ_ADD); | 1593 | i = kobject_init_and_add(&new_var->kobj, &efivar_ktype, |
1594 | NULL, "%s", short_name); | ||
1867 | kfree(short_name); | 1595 | kfree(short_name); |
1868 | short_name = NULL; | 1596 | if (i) |
1597 | return 1; | ||
1869 | 1598 | ||
1870 | spin_lock_irq(&efivars->lock); | 1599 | kobject_uevent(&new_var->kobj, KOBJ_ADD); |
1871 | list_add(&new_efivar->list, &efivars->list); | 1600 | efivar_entry_add(new_var, &efivar_sysfs_list); |
1872 | spin_unlock_irq(&efivars->lock); | ||
1873 | 1601 | ||
1874 | return 0; | 1602 | return 0; |
1875 | } | 1603 | } |
1876 | 1604 | ||
1877 | static int | 1605 | static int |
1878 | create_efivars_bin_attributes(struct efivars *efivars) | 1606 | create_efivars_bin_attributes(void) |
1879 | { | 1607 | { |
1880 | struct bin_attribute *attr; | 1608 | struct bin_attribute *attr; |
1881 | int error; | 1609 | int error; |
@@ -1888,8 +1616,7 @@ create_efivars_bin_attributes(struct efivars *efivars) | |||
1888 | attr->attr.name = "new_var"; | 1616 | attr->attr.name = "new_var"; |
1889 | attr->attr.mode = 0200; | 1617 | attr->attr.mode = 0200; |
1890 | attr->write = efivar_create; | 1618 | attr->write = efivar_create; |
1891 | attr->private = efivars; | 1619 | efivars_new_var = attr; |
1892 | efivars->new_var = attr; | ||
1893 | 1620 | ||
1894 | /* del_var */ | 1621 | /* del_var */ |
1895 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | 1622 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
@@ -1900,61 +1627,59 @@ create_efivars_bin_attributes(struct efivars *efivars) | |||
1900 | attr->attr.name = "del_var"; | 1627 | attr->attr.name = "del_var"; |
1901 | attr->attr.mode = 0200; | 1628 | attr->attr.mode = 0200; |
1902 | attr->write = efivar_delete; | 1629 | attr->write = efivar_delete; |
1903 | attr->private = efivars; | 1630 | efivars_del_var = attr; |
1904 | efivars->del_var = attr; | ||
1905 | 1631 | ||
1906 | sysfs_bin_attr_init(efivars->new_var); | 1632 | sysfs_bin_attr_init(efivars_new_var); |
1907 | sysfs_bin_attr_init(efivars->del_var); | 1633 | sysfs_bin_attr_init(efivars_del_var); |
1908 | 1634 | ||
1909 | /* Register */ | 1635 | /* Register */ |
1910 | error = sysfs_create_bin_file(&efivars->kset->kobj, | 1636 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var); |
1911 | efivars->new_var); | ||
1912 | if (error) { | 1637 | if (error) { |
1913 | printk(KERN_ERR "efivars: unable to create new_var sysfs file" | 1638 | printk(KERN_ERR "efivars: unable to create new_var sysfs file" |
1914 | " due to error %d\n", error); | 1639 | " due to error %d\n", error); |
1915 | goto out_free; | 1640 | goto out_free; |
1916 | } | 1641 | } |
1917 | error = sysfs_create_bin_file(&efivars->kset->kobj, | 1642 | |
1918 | efivars->del_var); | 1643 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var); |
1919 | if (error) { | 1644 | if (error) { |
1920 | printk(KERN_ERR "efivars: unable to create del_var sysfs file" | 1645 | printk(KERN_ERR "efivars: unable to create del_var sysfs file" |
1921 | " due to error %d\n", error); | 1646 | " due to error %d\n", error); |
1922 | sysfs_remove_bin_file(&efivars->kset->kobj, | 1647 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); |
1923 | efivars->new_var); | ||
1924 | goto out_free; | 1648 | goto out_free; |
1925 | } | 1649 | } |
1926 | 1650 | ||
1927 | return 0; | 1651 | return 0; |
1928 | out_free: | 1652 | out_free: |
1929 | kfree(efivars->del_var); | 1653 | kfree(efivars_del_var); |
1930 | efivars->del_var = NULL; | 1654 | efivars_del_var = NULL; |
1931 | kfree(efivars->new_var); | 1655 | kfree(efivars_new_var); |
1932 | efivars->new_var = NULL; | 1656 | efivars_new_var = NULL; |
1933 | return error; | 1657 | return error; |
1934 | } | 1658 | } |
1935 | 1659 | ||
1936 | void unregister_efivars(struct efivars *efivars) | 1660 | static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor, |
1661 | unsigned long name_size, void *data) | ||
1937 | { | 1662 | { |
1938 | struct efivar_entry *entry, *n; | 1663 | struct efivar_entry *entry; |
1939 | 1664 | ||
1940 | __efivars = NULL; | 1665 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
1666 | if (!entry) | ||
1667 | return -ENOMEM; | ||
1941 | 1668 | ||
1942 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | 1669 | memcpy(entry->var.VariableName, name, name_size); |
1943 | spin_lock_irq(&efivars->lock); | 1670 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); |
1944 | list_del(&entry->list); | 1671 | |
1945 | spin_unlock_irq(&efivars->lock); | 1672 | efivar_create_sysfs_entry(entry); |
1946 | efivar_unregister(entry); | 1673 | |
1947 | } | 1674 | return 0; |
1948 | if (efivars->new_var) | 1675 | } |
1949 | sysfs_remove_bin_file(&efivars->kset->kobj, efivars->new_var); | 1676 | |
1950 | if (efivars->del_var) | 1677 | static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) |
1951 | sysfs_remove_bin_file(&efivars->kset->kobj, efivars->del_var); | 1678 | { |
1952 | kfree(efivars->new_var); | 1679 | efivar_entry_remove(entry); |
1953 | kfree(efivars->del_var); | 1680 | efivar_unregister(entry); |
1954 | kobject_put(efivars->kobject); | 1681 | return 0; |
1955 | kset_unregister(efivars->kset); | ||
1956 | } | 1682 | } |
1957 | EXPORT_SYMBOL_GPL(unregister_efivars); | ||
1958 | 1683 | ||
1959 | /* | 1684 | /* |
1960 | * Print a warning when duplicate EFI variables are encountered and | 1685 | * Print a warning when duplicate EFI variables are encountered and |
@@ -1985,43 +1710,91 @@ static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | |||
1985 | kfree(s8); | 1710 | kfree(s8); |
1986 | } | 1711 | } |
1987 | 1712 | ||
1988 | int register_efivars(struct efivars *efivars, | 1713 | static struct kobject *efivars_kobj; |
1989 | const struct efivar_operations *ops, | 1714 | |
1990 | struct kobject *parent_kobj) | 1715 | void efivars_sysfs_exit(void) |
1991 | { | 1716 | { |
1992 | efi_status_t status = EFI_NOT_FOUND; | 1717 | /* Remove all entries and destroy */ |
1993 | efi_guid_t vendor_guid; | 1718 | __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); |
1994 | efi_char16_t *variable_name; | 1719 | |
1995 | unsigned long variable_name_size = 1024; | 1720 | if (efivars_new_var) |
1996 | int error = 0; | 1721 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); |
1722 | if (efivars_del_var) | ||
1723 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var); | ||
1724 | kfree(efivars_new_var); | ||
1725 | kfree(efivars_del_var); | ||
1726 | kobject_put(efivars_kobj); | ||
1727 | kset_unregister(efivars_kset); | ||
1728 | } | ||
1997 | 1729 | ||
1998 | __efivars = efivars; | 1730 | int efivars_sysfs_init(void) |
1731 | { | ||
1732 | struct kobject *parent_kobj = efivars_kobject(); | ||
1733 | int error = 0; | ||
1999 | 1734 | ||
2000 | variable_name = kzalloc(variable_name_size, GFP_KERNEL); | 1735 | /* No efivars has been registered yet */ |
2001 | if (!variable_name) { | 1736 | if (!parent_kobj) |
2002 | printk(KERN_ERR "efivars: Memory allocation failed.\n"); | 1737 | return 0; |
2003 | return -ENOMEM; | ||
2004 | } | ||
2005 | 1738 | ||
2006 | spin_lock_init(&efivars->lock); | 1739 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, |
2007 | INIT_LIST_HEAD(&efivars->list); | 1740 | EFIVARS_DATE); |
2008 | efivars->ops = ops; | ||
2009 | 1741 | ||
2010 | efivars->kset = kset_create_and_add("vars", NULL, parent_kobj); | 1742 | efivars_kset = kset_create_and_add("vars", NULL, parent_kobj); |
2011 | if (!efivars->kset) { | 1743 | if (!efivars_kset) { |
2012 | printk(KERN_ERR "efivars: Subsystem registration failed.\n"); | 1744 | printk(KERN_ERR "efivars: Subsystem registration failed.\n"); |
2013 | error = -ENOMEM; | 1745 | return -ENOMEM; |
2014 | goto out; | ||
2015 | } | 1746 | } |
2016 | 1747 | ||
2017 | efivars->kobject = kobject_create_and_add("efivars", parent_kobj); | 1748 | efivars_kobj = kobject_create_and_add("efivars", parent_kobj); |
2018 | if (!efivars->kobject) { | 1749 | if (!efivars_kobj) { |
2019 | pr_err("efivars: Subsystem registration failed.\n"); | 1750 | pr_err("efivars: Subsystem registration failed.\n"); |
2020 | error = -ENOMEM; | 1751 | kset_unregister(efivars_kset); |
2021 | kset_unregister(efivars->kset); | 1752 | return -ENOMEM; |
2022 | goto out; | 1753 | } |
1754 | |||
1755 | efivar_init(efivars_sysfs_callback, NULL, false, | ||
1756 | true, &efivar_sysfs_list); | ||
1757 | |||
1758 | error = create_efivars_bin_attributes(); | ||
1759 | if (error) | ||
1760 | efivars_sysfs_exit(); | ||
1761 | |||
1762 | return error; | ||
1763 | } | ||
1764 | EXPORT_SYMBOL_GPL(efivars_sysfs_init); | ||
1765 | |||
1766 | /** | ||
1767 | * efivar_init - build the initial list of EFI variables | ||
1768 | * @func: callback function to invoke for every variable | ||
1769 | * @data: function-specific data to pass to @func | ||
1770 | * @atomic: do we need to execute the @func-loop atomically? | ||
1771 | * @duplicates: error if we encounter duplicates on @head? | ||
1772 | * @head: initialised head of variable list | ||
1773 | * | ||
1774 | * Get every EFI variable from the firmware and invoke @func. @func | ||
1775 | * should call efivar_entry_add() to build the list of variables. | ||
1776 | * | ||
1777 | * Returns 0 on success, or a kernel error code on failure. | ||
1778 | */ | ||
1779 | int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), | ||
1780 | void *data, bool atomic, bool duplicates, | ||
1781 | struct list_head *head) | ||
1782 | { | ||
1783 | const struct efivar_operations *ops = __efivars->ops; | ||
1784 | unsigned long variable_name_size = 1024; | ||
1785 | efi_char16_t *variable_name; | ||
1786 | efi_status_t status; | ||
1787 | efi_guid_t vendor_guid; | ||
1788 | int err = 0; | ||
1789 | |||
1790 | variable_name = kzalloc(variable_name_size, GFP_KERNEL); | ||
1791 | if (!variable_name) { | ||
1792 | printk(KERN_ERR "efivars: Memory allocation failed.\n"); | ||
1793 | return -ENOMEM; | ||
2023 | } | 1794 | } |
2024 | 1795 | ||
1796 | spin_lock_irq(&__efivars->lock); | ||
1797 | |||
2025 | /* | 1798 | /* |
2026 | * Per EFI spec, the maximum storage allocated for both | 1799 | * Per EFI spec, the maximum storage allocated for both |
2027 | * the variable name and variable data is 1024 bytes. | 1800 | * the variable name and variable data is 1024 bytes. |
@@ -2035,6 +1808,9 @@ int register_efivars(struct efivars *efivars, | |||
2035 | &vendor_guid); | 1808 | &vendor_guid); |
2036 | switch (status) { | 1809 | switch (status) { |
2037 | case EFI_SUCCESS: | 1810 | case EFI_SUCCESS: |
1811 | if (!atomic) | ||
1812 | spin_unlock_irq(&__efivars->lock); | ||
1813 | |||
2038 | variable_name_size = var_name_strnsize(variable_name, | 1814 | variable_name_size = var_name_strnsize(variable_name, |
2039 | variable_name_size); | 1815 | variable_name_size); |
2040 | 1816 | ||
@@ -2046,17 +1822,24 @@ int register_efivars(struct efivars *efivars, | |||
2046 | * we'll ever see a different variable name, | 1822 | * we'll ever see a different variable name, |
2047 | * and may end up looping here forever. | 1823 | * and may end up looping here forever. |
2048 | */ | 1824 | */ |
2049 | if (variable_is_present(variable_name, &vendor_guid)) { | 1825 | if (duplicates && |
1826 | variable_is_present(variable_name, &vendor_guid, head)) { | ||
2050 | dup_variable_bug(variable_name, &vendor_guid, | 1827 | dup_variable_bug(variable_name, &vendor_guid, |
2051 | variable_name_size); | 1828 | variable_name_size); |
1829 | if (!atomic) | ||
1830 | spin_lock_irq(&__efivars->lock); | ||
1831 | |||
2052 | status = EFI_NOT_FOUND; | 1832 | status = EFI_NOT_FOUND; |
2053 | break; | 1833 | break; |
2054 | } | 1834 | } |
2055 | 1835 | ||
2056 | efivar_create_sysfs_entry(efivars, | 1836 | err = func(variable_name, vendor_guid, variable_name_size, data); |
2057 | variable_name_size, | 1837 | if (err) |
2058 | variable_name, | 1838 | status = EFI_NOT_FOUND; |
2059 | &vendor_guid); | 1839 | |
1840 | if (!atomic) | ||
1841 | spin_lock_irq(&__efivars->lock); | ||
1842 | |||
2060 | break; | 1843 | break; |
2061 | case EFI_NOT_FOUND: | 1844 | case EFI_NOT_FOUND: |
2062 | break; | 1845 | break; |
@@ -2066,40 +1849,637 @@ int register_efivars(struct efivars *efivars, | |||
2066 | status = EFI_NOT_FOUND; | 1849 | status = EFI_NOT_FOUND; |
2067 | break; | 1850 | break; |
2068 | } | 1851 | } |
1852 | |||
2069 | } while (status != EFI_NOT_FOUND); | 1853 | } while (status != EFI_NOT_FOUND); |
2070 | 1854 | ||
2071 | error = create_efivars_bin_attributes(efivars); | 1855 | spin_unlock_irq(&__efivars->lock); |
2072 | if (error) | 1856 | |
2073 | unregister_efivars(efivars); | 1857 | kfree(variable_name); |
1858 | |||
1859 | return err; | ||
1860 | } | ||
1861 | EXPORT_SYMBOL_GPL(efivar_init); | ||
1862 | |||
1863 | /** | ||
1864 | * efivar_entry_add - add entry to variable list | ||
1865 | * @entry: entry to add to list | ||
1866 | * @head: list head | ||
1867 | */ | ||
1868 | void efivar_entry_add(struct efivar_entry *entry, struct list_head *head) | ||
1869 | { | ||
1870 | spin_lock_irq(&__efivars->lock); | ||
1871 | list_add(&entry->list, head); | ||
1872 | spin_unlock_irq(&__efivars->lock); | ||
1873 | } | ||
1874 | EXPORT_SYMBOL_GPL(efivar_entry_add); | ||
1875 | |||
1876 | /** | ||
1877 | * efivar_entry_remove - remove entry from variable list | ||
1878 | * @entry: entry to remove from list | ||
1879 | */ | ||
1880 | void efivar_entry_remove(struct efivar_entry *entry) | ||
1881 | { | ||
1882 | spin_lock_irq(&__efivars->lock); | ||
1883 | list_del(&entry->list); | ||
1884 | spin_unlock_irq(&__efivars->lock); | ||
1885 | } | ||
1886 | EXPORT_SYMBOL_GPL(efivar_entry_remove); | ||
1887 | |||
1888 | /* | ||
1889 | * efivar_entry_list_del_unlock - remove entry from variable list | ||
1890 | * @entry: entry to remove | ||
1891 | * | ||
1892 | * Remove @entry from the variable list and release the list lock. | ||
1893 | * | ||
1894 | * NOTE: slightly weird locking semantics here - we expect to be | ||
1895 | * called with the efivars lock already held, and we release it before | ||
1896 | * returning. This is because this function is usually called after | ||
1897 | * set_variable() while the lock is still held. | ||
1898 | */ | ||
1899 | static void efivar_entry_list_del_unlock(struct efivar_entry *entry) | ||
1900 | { | ||
1901 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
1902 | |||
1903 | list_del(&entry->list); | ||
1904 | spin_unlock_irq(&__efivars->lock); | ||
1905 | } | ||
1906 | |||
1907 | /** | ||
1908 | * __efivar_entry_delete - delete an EFI variable | ||
1909 | * @entry: entry containing EFI variable to delete | ||
1910 | * | ||
1911 | * Delete the variable from the firmware and remove @entry from the | ||
1912 | * variable list. It is the caller's responsibility to free @entry | ||
1913 | * once we return. | ||
1914 | * | ||
1915 | * This function differs from efivar_entry_delete() because it is | ||
1916 | * safe to be called from within a efivar_entry_iter_begin() and | ||
1917 | * efivar_entry_iter_end() region, unlike efivar_entry_delete(). | ||
1918 | * | ||
1919 | * Returns 0 on success, or a converted EFI status code if | ||
1920 | * set_variable() fails. If set_variable() fails the entry remains | ||
1921 | * on the list. | ||
1922 | */ | ||
1923 | int __efivar_entry_delete(struct efivar_entry *entry) | ||
1924 | { | ||
1925 | const struct efivar_operations *ops = __efivars->ops; | ||
1926 | efi_status_t status; | ||
1927 | |||
1928 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
1929 | |||
1930 | status = ops->set_variable(entry->var.VariableName, | ||
1931 | &entry->var.VendorGuid, | ||
1932 | 0, 0, NULL); | ||
1933 | if (status) | ||
1934 | return efi_status_to_err(status); | ||
1935 | |||
1936 | list_del(&entry->list); | ||
1937 | |||
1938 | return 0; | ||
1939 | } | ||
1940 | EXPORT_SYMBOL_GPL(__efivar_entry_delete); | ||
1941 | |||
1942 | /** | ||
1943 | * efivar_entry_delete - delete variable and remove entry from list | ||
1944 | * @entry: entry containing variable to delete | ||
1945 | * | ||
1946 | * Delete the variable from the firmware and remove @entry from the | ||
1947 | * variable list. It is the caller's responsibility to free @entry | ||
1948 | * once we return. | ||
1949 | * | ||
1950 | * Returns 0 on success, or a converted EFI status code if | ||
1951 | * set_variable() fails. | ||
1952 | */ | ||
1953 | int efivar_entry_delete(struct efivar_entry *entry) | ||
1954 | { | ||
1955 | const struct efivar_operations *ops = __efivars->ops; | ||
1956 | efi_status_t status; | ||
1957 | |||
1958 | spin_lock_irq(&__efivars->lock); | ||
1959 | status = ops->set_variable(entry->var.VariableName, | ||
1960 | &entry->var.VendorGuid, | ||
1961 | 0, 0, NULL); | ||
1962 | if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { | ||
1963 | spin_unlock_irq(&__efivars->lock); | ||
1964 | return efi_status_to_err(status); | ||
1965 | } | ||
1966 | |||
1967 | efivar_entry_list_del_unlock(entry); | ||
1968 | return 0; | ||
1969 | } | ||
1970 | EXPORT_SYMBOL_GPL(efivar_entry_delete); | ||
1971 | |||
1972 | /** | ||
1973 | * efivar_entry_set - call set_variable() | ||
1974 | * @entry: entry containing the EFI variable to write | ||
1975 | * @attributes: variable attributes | ||
1976 | * @size: size of @data buffer | ||
1977 | * @data: buffer containing variable data | ||
1978 | * @head: head of variable list | ||
1979 | * | ||
1980 | * Calls set_variable() for an EFI variable. If creating a new EFI | ||
1981 | * variable, this function is usually followed by efivar_entry_add(). | ||
1982 | * | ||
1983 | * Before writing the variable, the remaining EFI variable storage | ||
1984 | * space is checked to ensure there is enough room available. | ||
1985 | * | ||
1986 | * If @head is not NULL a lookup is performed to determine whether | ||
1987 | * the entry is already on the list. | ||
1988 | * | ||
1989 | * Returns 0 on success, -EEXIST if a lookup is performed and the entry | ||
1990 | * already exists on the list, or a converted EFI status code if | ||
1991 | * set_variable() fails. | ||
1992 | */ | ||
1993 | int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | ||
1994 | unsigned long size, void *data, struct list_head *head) | ||
1995 | { | ||
1996 | const struct efivar_operations *ops = __efivars->ops; | ||
1997 | efi_status_t status; | ||
1998 | efi_char16_t *name = entry->var.VariableName; | ||
1999 | efi_guid_t vendor = entry->var.VendorGuid; | ||
2000 | |||
2001 | spin_lock_irq(&__efivars->lock); | ||
2002 | |||
2003 | if (head && efivar_entry_find(name, vendor, head, false)) { | ||
2004 | spin_unlock_irq(&__efivars->lock); | ||
2005 | return -EEXIST; | ||
2006 | } | ||
2007 | |||
2008 | status = check_var_size(attributes, size + utf16_strsize(name, 1024)); | ||
2009 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) | ||
2010 | status = ops->set_variable(name, &vendor, | ||
2011 | attributes, size, data); | ||
2012 | |||
2013 | spin_unlock_irq(&__efivars->lock); | ||
2014 | |||
2015 | return efi_status_to_err(status); | ||
2016 | } | ||
2017 | EXPORT_SYMBOL_GPL(efivar_entry_set); | ||
2018 | |||
2019 | /** | ||
2020 | * efivar_entry_set_safe - call set_variable() if enough space in firmware | ||
2021 | * @name: buffer containing the variable name | ||
2022 | * @vendor: variable vendor guid | ||
2023 | * @attributes: variable attributes | ||
2024 | * @block: can we block in this context? | ||
2025 | * @size: size of @data buffer | ||
2026 | * @data: buffer containing variable data | ||
2027 | * | ||
2028 | * Ensures there is enough free storage in the firmware for this variable, and | ||
2029 | * if so, calls set_variable(). If creating a new EFI variable, this function | ||
2030 | * is usually followed by efivar_entry_add(). | ||
2031 | * | ||
2032 | * Returns 0 on success, -ENOSPC if the firmware does not have enough | ||
2033 | * space for set_variable() to succeed, or a converted EFI status code | ||
2034 | * if set_variable() fails. | ||
2035 | */ | ||
2036 | int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | ||
2037 | bool block, unsigned long size, void *data) | ||
2038 | { | ||
2039 | const struct efivar_operations *ops = __efivars->ops; | ||
2040 | unsigned long flags; | ||
2041 | efi_status_t status; | ||
2042 | |||
2043 | if (!ops->query_variable_info) | ||
2044 | return -ENOSYS; | ||
2045 | |||
2046 | if (!block && !spin_trylock_irqsave(&__efivars->lock, flags)) | ||
2047 | return -EBUSY; | ||
2048 | else | ||
2049 | spin_lock_irqsave(&__efivars->lock, flags); | ||
2050 | |||
2051 | status = check_var_size(attributes, size + utf16_strsize(name, 1024)); | ||
2052 | if (status != EFI_SUCCESS) { | ||
2053 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
2054 | return -ENOSPC; | ||
2055 | } | ||
2056 | |||
2057 | status = ops->set_variable(name, &vendor, attributes, size, data); | ||
2058 | |||
2059 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
2060 | |||
2061 | return efi_status_to_err(status); | ||
2062 | } | ||
2063 | EXPORT_SYMBOL_GPL(efivar_entry_set_safe); | ||
2064 | |||
2065 | /** | ||
2066 | * efivar_entry_find - search for an entry | ||
2067 | * @name: the EFI variable name | ||
2068 | * @guid: the EFI variable vendor's guid | ||
2069 | * @head: head of the variable list | ||
2070 | * @remove: should we remove the entry from the list? | ||
2071 | * | ||
2072 | * Search for an entry on the variable list that has the EFI variable | ||
2073 | * name @name and vendor guid @guid. If an entry is found on the list | ||
2074 | * and @remove is true, the entry is removed from the list. | ||
2075 | * | ||
2076 | * The caller MUST call efivar_entry_iter_begin() and | ||
2077 | * efivar_entry_iter_end() before and after the invocation of this | ||
2078 | * function, respectively. | ||
2079 | * | ||
2080 | * Returns the entry if found on the list, %NULL otherwise. | ||
2081 | */ | ||
2082 | struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, | ||
2083 | struct list_head *head, bool remove) | ||
2084 | { | ||
2085 | struct efivar_entry *entry, *n; | ||
2086 | int strsize1, strsize2; | ||
2087 | bool found = false; | ||
2088 | |||
2089 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
2090 | |||
2091 | list_for_each_entry_safe(entry, n, head, list) { | ||
2092 | strsize1 = utf16_strsize(name, 1024); | ||
2093 | strsize2 = utf16_strsize(entry->var.VariableName, 1024); | ||
2094 | if (strsize1 == strsize2 && | ||
2095 | !memcmp(name, &(entry->var.VariableName), strsize1) && | ||
2096 | !efi_guidcmp(guid, entry->var.VendorGuid)) { | ||
2097 | found = true; | ||
2098 | break; | ||
2099 | } | ||
2100 | } | ||
2101 | |||
2102 | if (!found) | ||
2103 | return NULL; | ||
2104 | |||
2105 | if (remove) | ||
2106 | list_del(&entry->list); | ||
2107 | |||
2108 | return entry; | ||
2109 | } | ||
2110 | EXPORT_SYMBOL_GPL(efivar_entry_find); | ||
2111 | |||
2112 | /** | ||
2113 | * __efivar_entry_size - obtain the size of a variable | ||
2114 | * @entry: entry for this variable | ||
2115 | * @size: location to store the variable's size | ||
2116 | * | ||
2117 | * The caller MUST call efivar_entry_iter_begin() and | ||
2118 | * efivar_entry_iter_end() before and after the invocation of this | ||
2119 | * function, respectively. | ||
2120 | */ | ||
2121 | int __efivar_entry_size(struct efivar_entry *entry, unsigned long *size) | ||
2122 | { | ||
2123 | const struct efivar_operations *ops = __efivars->ops; | ||
2124 | efi_status_t status; | ||
2125 | |||
2126 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
2127 | |||
2128 | *size = 0; | ||
2129 | status = ops->get_variable(entry->var.VariableName, | ||
2130 | &entry->var.VendorGuid, NULL, size, NULL); | ||
2131 | if (status != EFI_BUFFER_TOO_SMALL) | ||
2132 | return efi_status_to_err(status); | ||
2133 | |||
2134 | return 0; | ||
2135 | } | ||
2136 | EXPORT_SYMBOL_GPL(__efivar_entry_size); | ||
2137 | |||
2138 | /** | ||
2139 | * efivar_entry_size - obtain the size of a variable | ||
2140 | * @entry: entry for this variable | ||
2141 | * @size: location to store the variable's size | ||
2142 | */ | ||
2143 | int efivar_entry_size(struct efivar_entry *entry, unsigned long *size) | ||
2144 | { | ||
2145 | const struct efivar_operations *ops = __efivars->ops; | ||
2146 | efi_status_t status; | ||
2147 | |||
2148 | *size = 0; | ||
2149 | |||
2150 | spin_lock_irq(&__efivars->lock); | ||
2151 | status = ops->get_variable(entry->var.VariableName, | ||
2152 | &entry->var.VendorGuid, NULL, size, NULL); | ||
2153 | spin_unlock_irq(&__efivars->lock); | ||
2154 | |||
2155 | if (status != EFI_BUFFER_TOO_SMALL) | ||
2156 | return efi_status_to_err(status); | ||
2157 | |||
2158 | return 0; | ||
2159 | } | ||
2160 | EXPORT_SYMBOL_GPL(efivar_entry_size); | ||
2161 | |||
2162 | /** | ||
2163 | * efivar_entry_get - call get_variable() | ||
2164 | * @entry: read data for this variable | ||
2165 | * @attributes: variable attributes | ||
2166 | * @size: size of @data buffer | ||
2167 | * @data: buffer to store variable data | ||
2168 | */ | ||
2169 | int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, | ||
2170 | unsigned long *size, void *data) | ||
2171 | { | ||
2172 | const struct efivar_operations *ops = __efivars->ops; | ||
2173 | efi_status_t status; | ||
2174 | |||
2175 | spin_lock_irq(&__efivars->lock); | ||
2176 | status = ops->get_variable(entry->var.VariableName, | ||
2177 | &entry->var.VendorGuid, | ||
2178 | attributes, size, data); | ||
2179 | spin_unlock_irq(&__efivars->lock); | ||
2180 | |||
2181 | return efi_status_to_err(status); | ||
2182 | } | ||
2183 | EXPORT_SYMBOL_GPL(efivar_entry_get); | ||
2184 | |||
2185 | /** | ||
2186 | * efivar_entry_set_get_size - call set_variable() and get new size (atomic) | ||
2187 | * @entry: entry containing variable to set and get | ||
2188 | * @attributes: attributes of variable to be written | ||
2189 | * @size: size of data buffer | ||
2190 | * @data: buffer containing data to write | ||
2191 | * @set: did the set_variable() call succeed? | ||
2192 | * | ||
2193 | * This is a pretty special (complex) function. See efivarfs_file_write(). | ||
2194 | * | ||
2195 | * Atomically call set_variable() for @entry and if the call is | ||
2196 | * successful, return the new size of the variable from get_variable() | ||
2197 | * in @size. The success of set_variable() is indicated by @set. | ||
2198 | * | ||
2199 | * Returns 0 on success, -EINVAL if the variable data is invalid, | ||
2200 | * -ENOSPC if the firmware does not have enough available space, or a | ||
2201 | * converted EFI status code if either of set_variable() or | ||
2202 | * get_variable() fail. | ||
2203 | * | ||
2204 | * If the EFI variable does not exist when calling set_variable() | ||
2205 | * (EFI_NOT_FOUND), @entry is removed from the variable list. | ||
2206 | */ | ||
2207 | int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, | ||
2208 | unsigned long *size, void *data, bool *set) | ||
2209 | { | ||
2210 | const struct efivar_operations *ops = __efivars->ops; | ||
2211 | efi_char16_t *name = entry->var.VariableName; | ||
2212 | efi_guid_t *vendor = &entry->var.VendorGuid; | ||
2213 | efi_status_t status; | ||
2214 | int err; | ||
2215 | |||
2216 | *set = false; | ||
2217 | |||
2218 | if (efivar_validate(&entry->var, data, *size) == false) | ||
2219 | return -EINVAL; | ||
2220 | |||
2221 | /* | ||
2222 | * The lock here protects the get_variable call, the conditional | ||
2223 | * set_variable call, and removal of the variable from the efivars | ||
2224 | * list (in the case of an authenticated delete). | ||
2225 | */ | ||
2226 | spin_lock_irq(&__efivars->lock); | ||
2227 | |||
2228 | /* | ||
2229 | * Ensure that the available space hasn't shrunk below the safe level | ||
2230 | */ | ||
2231 | status = check_var_size(attributes, *size + utf16_strsize(name, 1024)); | ||
2232 | if (status != EFI_SUCCESS) { | ||
2233 | if (status != EFI_UNSUPPORTED) { | ||
2234 | err = efi_status_to_err(status); | ||
2235 | goto out; | ||
2236 | } | ||
2237 | |||
2238 | if (*size > 65536) { | ||
2239 | err = -ENOSPC; | ||
2240 | goto out; | ||
2241 | } | ||
2242 | } | ||
2243 | |||
2244 | status = ops->set_variable(name, vendor, attributes, *size, data); | ||
2245 | if (status != EFI_SUCCESS) { | ||
2246 | err = efi_status_to_err(status); | ||
2247 | goto out; | ||
2248 | } | ||
2249 | |||
2250 | *set = true; | ||
2251 | |||
2252 | /* | ||
2253 | * Writing to the variable may have caused a change in size (which | ||
2254 | * could either be an append or an overwrite), or the variable to be | ||
2255 | * deleted. Perform a GetVariable() so we can tell what actually | ||
2256 | * happened. | ||
2257 | */ | ||
2258 | *size = 0; | ||
2259 | status = ops->get_variable(entry->var.VariableName, | ||
2260 | &entry->var.VendorGuid, | ||
2261 | NULL, size, NULL); | ||
2262 | |||
2263 | if (status == EFI_NOT_FOUND) | ||
2264 | efivar_entry_list_del_unlock(entry); | ||
2265 | else | ||
2266 | spin_unlock_irq(&__efivars->lock); | ||
2267 | |||
2268 | if (status && status != EFI_BUFFER_TOO_SMALL) | ||
2269 | return efi_status_to_err(status); | ||
2270 | |||
2271 | return 0; | ||
2272 | |||
2273 | out: | ||
2274 | spin_unlock_irq(&__efivars->lock); | ||
2275 | return err; | ||
2276 | |||
2277 | } | ||
2278 | EXPORT_SYMBOL_GPL(efivar_entry_set_get_size); | ||
2279 | |||
2280 | /** | ||
2281 | * efivar_entry_iter_begin - begin iterating the variable list | ||
2282 | * | ||
2283 | * Lock the variable list to prevent entry insertion and removal until | ||
2284 | * efivar_entry_iter_end() is called. This function is usually used in | ||
2285 | * conjunction with __efivar_entry_iter() or efivar_entry_iter(). | ||
2286 | */ | ||
2287 | void efivar_entry_iter_begin(void) | ||
2288 | { | ||
2289 | spin_lock_irq(&__efivars->lock); | ||
2290 | } | ||
2291 | EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); | ||
2292 | |||
2293 | /** | ||
2294 | * efivar_entry_iter_end - finish iterating the variable list | ||
2295 | * | ||
2296 | * Unlock the variable list and allow modifications to the list again. | ||
2297 | */ | ||
2298 | void efivar_entry_iter_end(void) | ||
2299 | { | ||
2300 | spin_unlock_irq(&__efivars->lock); | ||
2301 | } | ||
2302 | EXPORT_SYMBOL_GPL(efivar_entry_iter_end); | ||
2303 | |||
2304 | /** | ||
2305 | * __efivar_entry_iter - iterate over variable list | ||
2306 | * @func: callback function | ||
2307 | * @head: head of the variable list | ||
2308 | * @data: function-specific data to pass to callback | ||
2309 | * @prev: entry to begin iterating from | ||
2310 | * | ||
2311 | * Iterate over the list of EFI variables and call @func with every | ||
2312 | * entry on the list. It is safe for @func to remove entries in the | ||
2313 | * list via efivar_entry_delete(). | ||
2314 | * | ||
2315 | * You MUST call efivar_enter_iter_begin() before this function, and | ||
2316 | * efivar_entry_iter_end() afterwards. | ||
2317 | * | ||
2318 | * It is possible to begin iteration from an arbitrary entry within | ||
2319 | * the list by passing @prev. @prev is updated on return to point to | ||
2320 | * the last entry passed to @func. To begin iterating from the | ||
2321 | * beginning of the list @prev must be %NULL. | ||
2322 | * | ||
2323 | * The restrictions for @func are the same as documented for | ||
2324 | * efivar_entry_iter(). | ||
2325 | */ | ||
2326 | int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *), | ||
2327 | struct list_head *head, void *data, | ||
2328 | struct efivar_entry **prev) | ||
2329 | { | ||
2330 | struct efivar_entry *entry, *n; | ||
2331 | int err = 0; | ||
2332 | |||
2333 | if (!prev || !*prev) { | ||
2334 | list_for_each_entry_safe(entry, n, head, list) { | ||
2335 | err = func(entry, data); | ||
2336 | if (err) | ||
2337 | break; | ||
2338 | } | ||
2339 | |||
2340 | if (prev) | ||
2341 | *prev = entry; | ||
2342 | |||
2343 | return err; | ||
2344 | } | ||
2345 | |||
2346 | |||
2347 | list_for_each_entry_safe_continue((*prev), n, head, list) { | ||
2348 | err = func(*prev, data); | ||
2349 | if (err) | ||
2350 | break; | ||
2351 | } | ||
2352 | |||
2353 | return err; | ||
2354 | } | ||
2355 | EXPORT_SYMBOL_GPL(__efivar_entry_iter); | ||
2356 | |||
2357 | /** | ||
2358 | * efivar_entry_iter - iterate over variable list | ||
2359 | * @func: callback function | ||
2360 | * @head: head of variable list | ||
2361 | * @data: function-specific data to pass to callback | ||
2362 | * | ||
2363 | * Iterate over the list of EFI variables and call @func with every | ||
2364 | * entry on the list. It is safe for @func to remove entries in the | ||
2365 | * list via efivar_entry_delete() while iterating. | ||
2366 | * | ||
2367 | * Some notes for the callback function: | ||
2368 | * - a non-zero return value indicates an error and terminates the loop | ||
2369 | * - @func is called from atomic context | ||
2370 | */ | ||
2371 | int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), | ||
2372 | struct list_head *head, void *data) | ||
2373 | { | ||
2374 | int err = 0; | ||
2375 | |||
2376 | efivar_entry_iter_begin(); | ||
2377 | err = __efivar_entry_iter(func, head, data, NULL); | ||
2378 | efivar_entry_iter_end(); | ||
2379 | |||
2380 | return err; | ||
2381 | } | ||
2382 | EXPORT_SYMBOL_GPL(efivar_entry_iter); | ||
2383 | |||
2384 | /** | ||
2385 | * efivars_kobject - get the kobject for the registered efivars | ||
2386 | * | ||
2387 | * If efivars_register() has not been called we return NULL, | ||
2388 | * otherwise return the kobject used at registration time. | ||
2389 | */ | ||
2390 | struct kobject *efivars_kobject(void) | ||
2391 | { | ||
2392 | if (!__efivars) | ||
2393 | return NULL; | ||
2394 | |||
2395 | return __efivars->kobject; | ||
2396 | } | ||
2397 | EXPORT_SYMBOL_GPL(efivars_kobject); | ||
2398 | |||
2399 | /** | ||
2400 | * efivars_register - register an efivars | ||
2401 | * @efivars: efivars to register | ||
2402 | * @ops: efivars operations | ||
2403 | * @kobject: @efivars-specific kobject | ||
2404 | * | ||
2405 | * Only a single efivars can be registered at any time. | ||
2406 | */ | ||
2407 | int efivars_register(struct efivars *efivars, | ||
2408 | const struct efivar_operations *ops, | ||
2409 | struct kobject *kobject) | ||
2410 | { | ||
2411 | spin_lock_init(&efivars->lock); | ||
2412 | efivars->ops = ops; | ||
2413 | efivars->kobject = kobject; | ||
2414 | |||
2415 | __efivars = efivars; | ||
2074 | 2416 | ||
2075 | if (!efivars_pstore_disable) | 2417 | if (!efivars_pstore_disable) |
2076 | efivar_pstore_register(efivars); | 2418 | efivar_pstore_register(); |
2077 | 2419 | ||
2078 | register_filesystem(&efivarfs_type); | 2420 | register_filesystem(&efivarfs_type); |
2079 | 2421 | ||
2080 | out: | 2422 | return 0; |
2081 | kfree(variable_name); | 2423 | } |
2424 | EXPORT_SYMBOL_GPL(efivars_register); | ||
2082 | 2425 | ||
2083 | return error; | 2426 | /** |
2427 | * efivars_unregister - unregister an efivars | ||
2428 | * @efivars: efivars to unregister | ||
2429 | * | ||
2430 | * The caller must have already removed every entry from the list, | ||
2431 | * failure to do so is an error. | ||
2432 | */ | ||
2433 | int efivars_unregister(struct efivars *efivars) | ||
2434 | { | ||
2435 | int rv; | ||
2436 | |||
2437 | if (!__efivars) { | ||
2438 | printk(KERN_ERR "efivars not registered\n"); | ||
2439 | rv = -EINVAL; | ||
2440 | goto out; | ||
2441 | } | ||
2442 | |||
2443 | if (__efivars != efivars) { | ||
2444 | rv = -EINVAL; | ||
2445 | goto out; | ||
2446 | } | ||
2447 | |||
2448 | __efivars = NULL; | ||
2449 | |||
2450 | rv = 0; | ||
2451 | out: | ||
2452 | return rv; | ||
2084 | } | 2453 | } |
2085 | EXPORT_SYMBOL_GPL(register_efivars); | 2454 | EXPORT_SYMBOL_GPL(efivars_unregister); |
2086 | 2455 | ||
2087 | static struct efivars generic_efivars; | 2456 | static struct efivars generic_efivars; |
2088 | static struct efivar_operations generic_ops; | 2457 | static struct efivar_operations generic_ops; |
2089 | 2458 | ||
2090 | static int generic_ops_register(void) | 2459 | static int generic_ops_register(void) |
2091 | { | 2460 | { |
2461 | int error; | ||
2462 | |||
2092 | generic_ops.get_variable = efi.get_variable; | 2463 | generic_ops.get_variable = efi.get_variable; |
2093 | generic_ops.set_variable = efi.set_variable; | 2464 | generic_ops.set_variable = efi.set_variable; |
2094 | generic_ops.get_next_variable = efi.get_next_variable; | 2465 | generic_ops.get_next_variable = efi.get_next_variable; |
2095 | generic_ops.query_variable_info = efi.query_variable_info; | 2466 | generic_ops.query_variable_info = efi.query_variable_info; |
2096 | 2467 | ||
2097 | return register_efivars(&generic_efivars, &generic_ops, efi_kobj); | 2468 | error = efivars_register(&generic_efivars, &generic_ops, efi_kobj); |
2469 | if (error) | ||
2470 | return error; | ||
2471 | |||
2472 | error = efivars_sysfs_init(); | ||
2473 | if (error) | ||
2474 | efivars_unregister(&generic_efivars); | ||
2475 | |||
2476 | return error; | ||
2098 | } | 2477 | } |
2099 | 2478 | ||
2100 | static void generic_ops_unregister(void) | 2479 | static void generic_ops_unregister(void) |
2101 | { | 2480 | { |
2102 | unregister_efivars(&generic_efivars); | 2481 | efivars_sysfs_exit(); |
2482 | efivars_unregister(&generic_efivars); | ||
2103 | } | 2483 | } |
2104 | 2484 | ||
2105 | /* | 2485 | /* |
@@ -2113,15 +2493,12 @@ static void generic_ops_unregister(void) | |||
2113 | static int __init | 2493 | static int __init |
2114 | efivars_init(void) | 2494 | efivars_init(void) |
2115 | { | 2495 | { |
2116 | int error = 0; | 2496 | int error; |
2117 | |||
2118 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, | ||
2119 | EFIVARS_DATE); | ||
2120 | 2497 | ||
2121 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) | 2498 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) |
2122 | return 0; | 2499 | return 0; |
2123 | 2500 | ||
2124 | /* For now we'll register the efi directory at /sys/firmware/efi */ | 2501 | /* Register the efi directory at /sys/firmware/efi */ |
2125 | efi_kobj = kobject_create_and_add("efi", firmware_kobj); | 2502 | efi_kobj = kobject_create_and_add("efi", firmware_kobj); |
2126 | if (!efi_kobj) { | 2503 | if (!efi_kobj) { |
2127 | printk(KERN_ERR "efivars: Firmware registration failed.\n"); | 2504 | printk(KERN_ERR "efivars: Firmware registration failed.\n"); |
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index c409a7577afc..757b2d92d5b0 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c | |||
@@ -882,12 +882,19 @@ static __init int gsmi_init(void) | |||
882 | goto out_remove_bin_file; | 882 | goto out_remove_bin_file; |
883 | } | 883 | } |
884 | 884 | ||
885 | ret = register_efivars(&efivars, &efivar_ops, gsmi_kobj); | 885 | ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj); |
886 | if (ret) { | 886 | if (ret) { |
887 | printk(KERN_INFO "gsmi: Failed to register efivars\n"); | 887 | printk(KERN_INFO "gsmi: Failed to register efivars\n"); |
888 | goto out_remove_sysfs_files; | 888 | goto out_remove_sysfs_files; |
889 | } | 889 | } |
890 | 890 | ||
891 | ret = efivars_sysfs_init(); | ||
892 | if (ret) { | ||
893 | printk(KERN_INFO "gsmi: Failed to create efivars files\n"); | ||
894 | efivars_unregister(&efivars); | ||
895 | goto out_remove_sysfs_files; | ||
896 | } | ||
897 | |||
891 | register_reboot_notifier(&gsmi_reboot_notifier); | 898 | register_reboot_notifier(&gsmi_reboot_notifier); |
892 | register_die_notifier(&gsmi_die_notifier); | 899 | register_die_notifier(&gsmi_die_notifier); |
893 | atomic_notifier_chain_register(&panic_notifier_list, | 900 | atomic_notifier_chain_register(&panic_notifier_list, |
@@ -919,7 +926,7 @@ static void __exit gsmi_exit(void) | |||
919 | unregister_die_notifier(&gsmi_die_notifier); | 926 | unregister_die_notifier(&gsmi_die_notifier); |
920 | atomic_notifier_chain_unregister(&panic_notifier_list, | 927 | atomic_notifier_chain_unregister(&panic_notifier_list, |
921 | &gsmi_panic_notifier); | 928 | &gsmi_panic_notifier); |
922 | unregister_efivars(&efivars); | 929 | efivars_unregister(&efivars); |
923 | 930 | ||
924 | sysfs_remove_files(gsmi_kobj, gsmi_attrs); | 931 | sysfs_remove_files(gsmi_kobj, gsmi_attrs); |
925 | sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); | 932 | sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); |
diff --git a/include/linux/efi.h b/include/linux/efi.h index d1d782a6d34c..cd561b301e6a 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -663,6 +663,12 @@ static inline int efi_enabled(int facility) | |||
663 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ | 663 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ |
664 | EFI_VARIABLE_APPEND_WRITE) | 664 | EFI_VARIABLE_APPEND_WRITE) |
665 | /* | 665 | /* |
666 | * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")) | ||
667 | * not including trailing NUL | ||
668 | */ | ||
669 | #define EFI_VARIABLE_GUID_LEN 36 | ||
670 | |||
671 | /* | ||
666 | * The type of search to perform when calling boottime->locate_handle | 672 | * The type of search to perform when calling boottime->locate_handle |
667 | */ | 673 | */ |
668 | #define EFI_LOCATE_ALL_HANDLES 0 | 674 | #define EFI_LOCATE_ALL_HANDLES 0 |
@@ -762,19 +768,75 @@ struct efivars { | |||
762 | * which is protected by the BKL, so that path is safe. | 768 | * which is protected by the BKL, so that path is safe. |
763 | */ | 769 | */ |
764 | spinlock_t lock; | 770 | spinlock_t lock; |
765 | struct list_head list; | ||
766 | struct kset *kset; | 771 | struct kset *kset; |
767 | struct kobject *kobject; | 772 | struct kobject *kobject; |
768 | struct bin_attribute *new_var, *del_var; | ||
769 | const struct efivar_operations *ops; | 773 | const struct efivar_operations *ops; |
770 | struct efivar_entry *walk_entry; | ||
771 | struct pstore_info efi_pstore_info; | ||
772 | }; | 774 | }; |
773 | 775 | ||
774 | int register_efivars(struct efivars *efivars, | 776 | /* |
777 | * The maximum size of VariableName + Data = 1024 | ||
778 | * Therefore, it's reasonable to save that much | ||
779 | * space in each part of the structure, | ||
780 | * and we use a page for reading/writing. | ||
781 | */ | ||
782 | |||
783 | struct efi_variable { | ||
784 | efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; | ||
785 | efi_guid_t VendorGuid; | ||
786 | unsigned long DataSize; | ||
787 | __u8 Data[1024]; | ||
788 | efi_status_t Status; | ||
789 | __u32 Attributes; | ||
790 | } __attribute__((packed)); | ||
791 | |||
792 | struct efivar_entry { | ||
793 | struct efi_variable var; | ||
794 | struct list_head list; | ||
795 | struct kobject kobj; | ||
796 | }; | ||
797 | |||
798 | int efivars_register(struct efivars *efivars, | ||
775 | const struct efivar_operations *ops, | 799 | const struct efivar_operations *ops, |
776 | struct kobject *parent_kobj); | 800 | struct kobject *kobject); |
777 | void unregister_efivars(struct efivars *efivars); | 801 | int efivars_unregister(struct efivars *efivars); |
802 | struct kobject *efivars_kobject(void); | ||
803 | |||
804 | int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), | ||
805 | void *data, bool atomic, bool duplicates, | ||
806 | struct list_head *head); | ||
807 | |||
808 | void efivar_entry_add(struct efivar_entry *entry, struct list_head *head); | ||
809 | void efivar_entry_remove(struct efivar_entry *entry); | ||
810 | |||
811 | int __efivar_entry_delete(struct efivar_entry *entry); | ||
812 | int efivar_entry_delete(struct efivar_entry *entry); | ||
813 | |||
814 | int __efivar_entry_size(struct efivar_entry *entry, unsigned long *size); | ||
815 | int efivar_entry_size(struct efivar_entry *entry, unsigned long *size); | ||
816 | int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, | ||
817 | unsigned long *size, void *data); | ||
818 | int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | ||
819 | unsigned long size, void *data, struct list_head *head); | ||
820 | int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, | ||
821 | unsigned long *size, void *data, bool *set); | ||
822 | int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | ||
823 | bool block, unsigned long size, void *data); | ||
824 | |||
825 | void efivar_entry_iter_begin(void); | ||
826 | void efivar_entry_iter_end(void); | ||
827 | |||
828 | int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *), | ||
829 | struct list_head *head, void *data, | ||
830 | struct efivar_entry **prev); | ||
831 | int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), | ||
832 | struct list_head *head, void *data); | ||
833 | |||
834 | struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, | ||
835 | struct list_head *head, bool remove); | ||
836 | |||
837 | bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); | ||
838 | |||
839 | int efivars_sysfs_init(void); | ||
778 | 840 | ||
779 | #endif /* CONFIG_EFI_VARS */ | 841 | #endif /* CONFIG_EFI_VARS */ |
780 | 842 | ||