aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi/vars.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/efi/vars.c')
-rw-r--r--drivers/firmware/efi/vars.c142
1 files changed, 88 insertions, 54 deletions
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index d3b751383286..9336ffdf6e2c 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -37,6 +37,14 @@
37/* Private pointer to registered efivars */ 37/* Private pointer to registered efivars */
38static struct efivars *__efivars; 38static struct efivars *__efivars;
39 39
40/*
41 * efivars_lock protects three things:
42 * 1) efivarfs_list and efivars_sysfs_list
43 * 2) ->ops calls
44 * 3) (un)registration of __efivars
45 */
46static DEFINE_SEMAPHORE(efivars_lock);
47
40static bool efivar_wq_enabled = true; 48static bool efivar_wq_enabled = true;
41DECLARE_WORK(efivar_work, NULL); 49DECLARE_WORK(efivar_work, NULL);
42EXPORT_SYMBOL_GPL(efivar_work); 50EXPORT_SYMBOL_GPL(efivar_work);
@@ -434,7 +442,10 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
434 return -ENOMEM; 442 return -ENOMEM;
435 } 443 }
436 444
437 spin_lock_irq(&__efivars->lock); 445 if (down_interruptible(&efivars_lock)) {
446 err = -EINTR;
447 goto free;
448 }
438 449
439 /* 450 /*
440 * Per EFI spec, the maximum storage allocated for both 451 * Per EFI spec, the maximum storage allocated for both
@@ -450,7 +461,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
450 switch (status) { 461 switch (status) {
451 case EFI_SUCCESS: 462 case EFI_SUCCESS:
452 if (duplicates) 463 if (duplicates)
453 spin_unlock_irq(&__efivars->lock); 464 up(&efivars_lock);
454 465
455 variable_name_size = var_name_strnsize(variable_name, 466 variable_name_size = var_name_strnsize(variable_name,
456 variable_name_size); 467 variable_name_size);
@@ -476,8 +487,12 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
476 status = EFI_NOT_FOUND; 487 status = EFI_NOT_FOUND;
477 } 488 }
478 489
479 if (duplicates) 490 if (duplicates) {
480 spin_lock_irq(&__efivars->lock); 491 if (down_interruptible(&efivars_lock)) {
492 err = -EINTR;
493 goto free;
494 }
495 }
481 496
482 break; 497 break;
483 case EFI_NOT_FOUND: 498 case EFI_NOT_FOUND:
@@ -491,8 +506,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
491 506
492 } while (status != EFI_NOT_FOUND); 507 } while (status != EFI_NOT_FOUND);
493 508
494 spin_unlock_irq(&__efivars->lock); 509 up(&efivars_lock);
495 510free:
496 kfree(variable_name); 511 kfree(variable_name);
497 512
498 return err; 513 return err;
@@ -503,24 +518,34 @@ EXPORT_SYMBOL_GPL(efivar_init);
503 * efivar_entry_add - add entry to variable list 518 * efivar_entry_add - add entry to variable list
504 * @entry: entry to add to list 519 * @entry: entry to add to list
505 * @head: list head 520 * @head: list head
521 *
522 * Returns 0 on success, or a kernel error code on failure.
506 */ 523 */
507void efivar_entry_add(struct efivar_entry *entry, struct list_head *head) 524int efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
508{ 525{
509 spin_lock_irq(&__efivars->lock); 526 if (down_interruptible(&efivars_lock))
527 return -EINTR;
510 list_add(&entry->list, head); 528 list_add(&entry->list, head);
511 spin_unlock_irq(&__efivars->lock); 529 up(&efivars_lock);
530
531 return 0;
512} 532}
513EXPORT_SYMBOL_GPL(efivar_entry_add); 533EXPORT_SYMBOL_GPL(efivar_entry_add);
514 534
515/** 535/**
516 * efivar_entry_remove - remove entry from variable list 536 * efivar_entry_remove - remove entry from variable list
517 * @entry: entry to remove from list 537 * @entry: entry to remove from list
538 *
539 * Returns 0 on success, or a kernel error code on failure.
518 */ 540 */
519void efivar_entry_remove(struct efivar_entry *entry) 541int efivar_entry_remove(struct efivar_entry *entry)
520{ 542{
521 spin_lock_irq(&__efivars->lock); 543 if (down_interruptible(&efivars_lock))
544 return -EINTR;
522 list_del(&entry->list); 545 list_del(&entry->list);
523 spin_unlock_irq(&__efivars->lock); 546 up(&efivars_lock);
547
548 return 0;
524} 549}
525EXPORT_SYMBOL_GPL(efivar_entry_remove); 550EXPORT_SYMBOL_GPL(efivar_entry_remove);
526 551
@@ -537,10 +562,8 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove);
537 */ 562 */
538static void efivar_entry_list_del_unlock(struct efivar_entry *entry) 563static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
539{ 564{
540 lockdep_assert_held(&__efivars->lock);
541
542 list_del(&entry->list); 565 list_del(&entry->list);
543 spin_unlock_irq(&__efivars->lock); 566 up(&efivars_lock);
544} 567}
545 568
546/** 569/**
@@ -563,8 +586,6 @@ int __efivar_entry_delete(struct efivar_entry *entry)
563 const struct efivar_operations *ops = __efivars->ops; 586 const struct efivar_operations *ops = __efivars->ops;
564 efi_status_t status; 587 efi_status_t status;
565 588
566 lockdep_assert_held(&__efivars->lock);
567
568 status = ops->set_variable(entry->var.VariableName, 589 status = ops->set_variable(entry->var.VariableName,
569 &entry->var.VendorGuid, 590 &entry->var.VendorGuid,
570 0, 0, NULL); 591 0, 0, NULL);
@@ -581,20 +602,22 @@ EXPORT_SYMBOL_GPL(__efivar_entry_delete);
581 * variable list. It is the caller's responsibility to free @entry 602 * variable list. It is the caller's responsibility to free @entry
582 * once we return. 603 * once we return.
583 * 604 *
584 * Returns 0 on success, or a converted EFI status code if 605 * Returns 0 on success, -EINTR if we can't grab the semaphore,
585 * set_variable() fails. 606 * converted EFI status code if set_variable() fails.
586 */ 607 */
587int efivar_entry_delete(struct efivar_entry *entry) 608int efivar_entry_delete(struct efivar_entry *entry)
588{ 609{
589 const struct efivar_operations *ops = __efivars->ops; 610 const struct efivar_operations *ops = __efivars->ops;
590 efi_status_t status; 611 efi_status_t status;
591 612
592 spin_lock_irq(&__efivars->lock); 613 if (down_interruptible(&efivars_lock))
614 return -EINTR;
615
593 status = ops->set_variable(entry->var.VariableName, 616 status = ops->set_variable(entry->var.VariableName,
594 &entry->var.VendorGuid, 617 &entry->var.VendorGuid,
595 0, 0, NULL); 618 0, 0, NULL);
596 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { 619 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
597 spin_unlock_irq(&__efivars->lock); 620 up(&efivars_lock);
598 return efi_status_to_err(status); 621 return efi_status_to_err(status);
599 } 622 }
600 623
@@ -620,9 +643,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_delete);
620 * If @head is not NULL a lookup is performed to determine whether 643 * If @head is not NULL a lookup is performed to determine whether
621 * the entry is already on the list. 644 * the entry is already on the list.
622 * 645 *
623 * Returns 0 on success, -EEXIST if a lookup is performed and the entry 646 * Returns 0 on success, -EINTR if we can't grab the semaphore,
624 * already exists on the list, or a converted EFI status code if 647 * -EEXIST if a lookup is performed and the entry already exists on
625 * set_variable() fails. 648 * the list, or a converted EFI status code if set_variable() fails.
626 */ 649 */
627int efivar_entry_set(struct efivar_entry *entry, u32 attributes, 650int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
628 unsigned long size, void *data, struct list_head *head) 651 unsigned long size, void *data, struct list_head *head)
@@ -632,10 +655,10 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
632 efi_char16_t *name = entry->var.VariableName; 655 efi_char16_t *name = entry->var.VariableName;
633 efi_guid_t vendor = entry->var.VendorGuid; 656 efi_guid_t vendor = entry->var.VendorGuid;
634 657
635 spin_lock_irq(&__efivars->lock); 658 if (down_interruptible(&efivars_lock))
636 659 return -EINTR;
637 if (head && efivar_entry_find(name, vendor, head, false)) { 660 if (head && efivar_entry_find(name, vendor, head, false)) {
638 spin_unlock_irq(&__efivars->lock); 661 up(&efivars_lock);
639 return -EEXIST; 662 return -EEXIST;
640 } 663 }
641 664
@@ -644,7 +667,7 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
644 status = ops->set_variable(name, &vendor, 667 status = ops->set_variable(name, &vendor,
645 attributes, size, data); 668 attributes, size, data);
646 669
647 spin_unlock_irq(&__efivars->lock); 670 up(&efivars_lock);
648 671
649 return efi_status_to_err(status); 672 return efi_status_to_err(status);
650 673
@@ -658,30 +681,29 @@ EXPORT_SYMBOL_GPL(efivar_entry_set);
658 * from crash/panic handlers. 681 * from crash/panic handlers.
659 * 682 *
660 * Crucially, this function will not block if it cannot acquire 683 * Crucially, this function will not block if it cannot acquire
661 * __efivars->lock. Instead, it returns -EBUSY. 684 * efivars_lock. Instead, it returns -EBUSY.
662 */ 685 */
663static int 686static int
664efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, 687efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
665 u32 attributes, unsigned long size, void *data) 688 u32 attributes, unsigned long size, void *data)
666{ 689{
667 const struct efivar_operations *ops = __efivars->ops; 690 const struct efivar_operations *ops = __efivars->ops;
668 unsigned long flags;
669 efi_status_t status; 691 efi_status_t status;
670 692
671 if (!spin_trylock_irqsave(&__efivars->lock, flags)) 693 if (down_trylock(&efivars_lock))
672 return -EBUSY; 694 return -EBUSY;
673 695
674 status = check_var_size_nonblocking(attributes, 696 status = check_var_size_nonblocking(attributes,
675 size + ucs2_strsize(name, 1024)); 697 size + ucs2_strsize(name, 1024));
676 if (status != EFI_SUCCESS) { 698 if (status != EFI_SUCCESS) {
677 spin_unlock_irqrestore(&__efivars->lock, flags); 699 up(&efivars_lock);
678 return -ENOSPC; 700 return -ENOSPC;
679 } 701 }
680 702
681 status = ops->set_variable_nonblocking(name, &vendor, attributes, 703 status = ops->set_variable_nonblocking(name, &vendor, attributes,
682 size, data); 704 size, data);
683 705
684 spin_unlock_irqrestore(&__efivars->lock, flags); 706 up(&efivars_lock);
685 return efi_status_to_err(status); 707 return efi_status_to_err(status);
686} 708}
687 709
@@ -706,7 +728,6 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
706 bool block, unsigned long size, void *data) 728 bool block, unsigned long size, void *data)
707{ 729{
708 const struct efivar_operations *ops = __efivars->ops; 730 const struct efivar_operations *ops = __efivars->ops;
709 unsigned long flags;
710 efi_status_t status; 731 efi_status_t status;
711 732
712 if (!ops->query_variable_store) 733 if (!ops->query_variable_store)
@@ -727,21 +748,22 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
727 size, data); 748 size, data);
728 749
729 if (!block) { 750 if (!block) {
730 if (!spin_trylock_irqsave(&__efivars->lock, flags)) 751 if (down_trylock(&efivars_lock))
731 return -EBUSY; 752 return -EBUSY;
732 } else { 753 } else {
733 spin_lock_irqsave(&__efivars->lock, flags); 754 if (down_interruptible(&efivars_lock))
755 return -EINTR;
734 } 756 }
735 757
736 status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); 758 status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
737 if (status != EFI_SUCCESS) { 759 if (status != EFI_SUCCESS) {
738 spin_unlock_irqrestore(&__efivars->lock, flags); 760 up(&efivars_lock);
739 return -ENOSPC; 761 return -ENOSPC;
740 } 762 }
741 763
742 status = ops->set_variable(name, &vendor, attributes, size, data); 764 status = ops->set_variable(name, &vendor, attributes, size, data);
743 765
744 spin_unlock_irqrestore(&__efivars->lock, flags); 766 up(&efivars_lock);
745 767
746 return efi_status_to_err(status); 768 return efi_status_to_err(status);
747} 769}
@@ -771,8 +793,6 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
771 int strsize1, strsize2; 793 int strsize1, strsize2;
772 bool found = false; 794 bool found = false;
773 795
774 lockdep_assert_held(&__efivars->lock);
775
776 list_for_each_entry_safe(entry, n, head, list) { 796 list_for_each_entry_safe(entry, n, head, list) {
777 strsize1 = ucs2_strsize(name, 1024); 797 strsize1 = ucs2_strsize(name, 1024);
778 strsize2 = ucs2_strsize(entry->var.VariableName, 1024); 798 strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
@@ -814,10 +834,11 @@ int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
814 834
815 *size = 0; 835 *size = 0;
816 836
817 spin_lock_irq(&__efivars->lock); 837 if (down_interruptible(&efivars_lock))
838 return -EINTR;
818 status = ops->get_variable(entry->var.VariableName, 839 status = ops->get_variable(entry->var.VariableName,
819 &entry->var.VendorGuid, NULL, size, NULL); 840 &entry->var.VendorGuid, NULL, size, NULL);
820 spin_unlock_irq(&__efivars->lock); 841 up(&efivars_lock);
821 842
822 if (status != EFI_BUFFER_TOO_SMALL) 843 if (status != EFI_BUFFER_TOO_SMALL)
823 return efi_status_to_err(status); 844 return efi_status_to_err(status);
@@ -843,8 +864,6 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
843 const struct efivar_operations *ops = __efivars->ops; 864 const struct efivar_operations *ops = __efivars->ops;
844 efi_status_t status; 865 efi_status_t status;
845 866
846 lockdep_assert_held(&__efivars->lock);
847
848 status = ops->get_variable(entry->var.VariableName, 867 status = ops->get_variable(entry->var.VariableName,
849 &entry->var.VendorGuid, 868 &entry->var.VendorGuid,
850 attributes, size, data); 869 attributes, size, data);
@@ -866,11 +885,12 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
866 const struct efivar_operations *ops = __efivars->ops; 885 const struct efivar_operations *ops = __efivars->ops;
867 efi_status_t status; 886 efi_status_t status;
868 887
869 spin_lock_irq(&__efivars->lock); 888 if (down_interruptible(&efivars_lock))
889 return -EINTR;
870 status = ops->get_variable(entry->var.VariableName, 890 status = ops->get_variable(entry->var.VariableName,
871 &entry->var.VendorGuid, 891 &entry->var.VendorGuid,
872 attributes, size, data); 892 attributes, size, data);
873 spin_unlock_irq(&__efivars->lock); 893 up(&efivars_lock);
874 894
875 return efi_status_to_err(status); 895 return efi_status_to_err(status);
876} 896}
@@ -917,7 +937,8 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
917 * set_variable call, and removal of the variable from the efivars 937 * set_variable call, and removal of the variable from the efivars
918 * list (in the case of an authenticated delete). 938 * list (in the case of an authenticated delete).
919 */ 939 */
920 spin_lock_irq(&__efivars->lock); 940 if (down_interruptible(&efivars_lock))
941 return -EINTR;
921 942
922 /* 943 /*
923 * Ensure that the available space hasn't shrunk below the safe level 944 * Ensure that the available space hasn't shrunk below the safe level
@@ -957,7 +978,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
957 if (status == EFI_NOT_FOUND) 978 if (status == EFI_NOT_FOUND)
958 efivar_entry_list_del_unlock(entry); 979 efivar_entry_list_del_unlock(entry);
959 else 980 else
960 spin_unlock_irq(&__efivars->lock); 981 up(&efivars_lock);
961 982
962 if (status && status != EFI_BUFFER_TOO_SMALL) 983 if (status && status != EFI_BUFFER_TOO_SMALL)
963 return efi_status_to_err(status); 984 return efi_status_to_err(status);
@@ -965,7 +986,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
965 return 0; 986 return 0;
966 987
967out: 988out:
968 spin_unlock_irq(&__efivars->lock); 989 up(&efivars_lock);
969 return err; 990 return err;
970 991
971} 992}
@@ -978,9 +999,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_set_get_size);
978 * efivar_entry_iter_end() is called. This function is usually used in 999 * efivar_entry_iter_end() is called. This function is usually used in
979 * conjunction with __efivar_entry_iter() or efivar_entry_iter(). 1000 * conjunction with __efivar_entry_iter() or efivar_entry_iter().
980 */ 1001 */
981void efivar_entry_iter_begin(void) 1002int efivar_entry_iter_begin(void)
982{ 1003{
983 spin_lock_irq(&__efivars->lock); 1004 return down_interruptible(&efivars_lock);
984} 1005}
985EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); 1006EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
986 1007
@@ -991,7 +1012,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
991 */ 1012 */
992void efivar_entry_iter_end(void) 1013void efivar_entry_iter_end(void)
993{ 1014{
994 spin_unlock_irq(&__efivars->lock); 1015 up(&efivars_lock);
995} 1016}
996EXPORT_SYMBOL_GPL(efivar_entry_iter_end); 1017EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
997 1018
@@ -1067,7 +1088,9 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
1067{ 1088{
1068 int err = 0; 1089 int err = 0;
1069 1090
1070 efivar_entry_iter_begin(); 1091 err = efivar_entry_iter_begin();
1092 if (err)
1093 return err;
1071 err = __efivar_entry_iter(func, head, data, NULL); 1094 err = __efivar_entry_iter(func, head, data, NULL);
1072 efivar_entry_iter_end(); 1095 efivar_entry_iter_end();
1073 1096
@@ -1112,12 +1135,18 @@ int efivars_register(struct efivars *efivars,
1112 const struct efivar_operations *ops, 1135 const struct efivar_operations *ops,
1113 struct kobject *kobject) 1136 struct kobject *kobject)
1114{ 1137{
1115 spin_lock_init(&efivars->lock); 1138 if (down_interruptible(&efivars_lock))
1139 return -EINTR;
1140
1116 efivars->ops = ops; 1141 efivars->ops = ops;
1117 efivars->kobject = kobject; 1142 efivars->kobject = kobject;
1118 1143
1119 __efivars = efivars; 1144 __efivars = efivars;
1120 1145
1146 pr_info("Registered efivars operations\n");
1147
1148 up(&efivars_lock);
1149
1121 return 0; 1150 return 0;
1122} 1151}
1123EXPORT_SYMBOL_GPL(efivars_register); 1152EXPORT_SYMBOL_GPL(efivars_register);
@@ -1133,6 +1162,9 @@ int efivars_unregister(struct efivars *efivars)
1133{ 1162{
1134 int rv; 1163 int rv;
1135 1164
1165 if (down_interruptible(&efivars_lock))
1166 return -EINTR;
1167
1136 if (!__efivars) { 1168 if (!__efivars) {
1137 printk(KERN_ERR "efivars not registered\n"); 1169 printk(KERN_ERR "efivars not registered\n");
1138 rv = -EINVAL; 1170 rv = -EINVAL;
@@ -1144,10 +1176,12 @@ int efivars_unregister(struct efivars *efivars)
1144 goto out; 1176 goto out;
1145 } 1177 }
1146 1178
1179 pr_info("Unregistered efivars operations\n");
1147 __efivars = NULL; 1180 __efivars = NULL;
1148 1181
1149 rv = 0; 1182 rv = 0;
1150out: 1183out:
1184 up(&efivars_lock);
1151 return rv; 1185 return rv;
1152} 1186}
1153EXPORT_SYMBOL_GPL(efivars_unregister); 1187EXPORT_SYMBOL_GPL(efivars_unregister);