1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/capability.h>
23#include <linux/types.h>
24#include <linux/errno.h>
25#include <linux/init.h>
26#include <linux/mm.h>
27#include <linux/module.h>
28#include <linux/string.h>
29#include <linux/smp.h>
30#include <linux/efi.h>
31#include <linux/sysfs.h>
32#include <linux/device.h>
33#include <linux/slab.h>
34#include <linux/ctype.h>
35#include <linux/ucs2_string.h>
36
37
38static struct efivars *__efivars;
39
40static bool efivar_wq_enabled = true;
41DECLARE_WORK(efivar_work, NULL);
42EXPORT_SYMBOL_GPL(efivar_work);
43
44static bool
45validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
46 unsigned long len)
47{
48 struct efi_generic_dev_path *node;
49 int offset = 0;
50
51 node = (struct efi_generic_dev_path *)buffer;
52
53 if (len < sizeof(*node))
54 return false;
55
56 while (offset <= len - sizeof(*node) &&
57 node->length >= sizeof(*node) &&
58 node->length <= len - offset) {
59 offset += node->length;
60
61 if ((node->type == EFI_DEV_END_PATH ||
62 node->type == EFI_DEV_END_PATH2) &&
63 node->sub_type == EFI_DEV_END_ENTIRE)
64 return true;
65
66 node = (struct efi_generic_dev_path *)(buffer + offset);
67 }
68
69
70
71
72
73
74 return false;
75}
76
77static bool
78validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer,
79 unsigned long len)
80{
81
82 if ((len % 2) != 0)
83 return false;
84
85 return true;
86}
87
88static bool
89validate_load_option(efi_char16_t *var_name, int match, u8 *buffer,
90 unsigned long len)
91{
92 u16 filepathlength;
93 int i, desclength = 0, namelen;
94
95 namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN);
96
97
98 for (i = match; i < match+4; i++) {
99 if (var_name[i] > 127 ||
100 hex_to_bin(var_name[i] & 0xff) < 0)
101 return true;
102 }
103
104
105 if (namelen > match + 4)
106 return false;
107
108
109 if (len < 8)
110 return false;
111
112 filepathlength = buffer[4] | buffer[5] << 8;
113
114
115
116
117
118 desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
119
120
121 if (!desclength)
122 return false;
123
124
125
126
127
128
129 if ((desclength + filepathlength + 6) > len)
130 return false;
131
132
133
134
135 return validate_device_path(var_name, match, buffer + desclength + 6,
136 filepathlength);
137}
138
139static bool
140validate_uint16(efi_char16_t *var_name, int match, u8 *buffer,
141 unsigned long len)
142{
143
144 if (len != 2)
145 return false;
146
147 return true;
148}
149
150static bool
151validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
152 unsigned long len)
153{
154 int i;
155
156 for (i = 0; i < len; i++) {
157 if (buffer[i] > 127)
158 return false;
159
160 if (buffer[i] == 0)
161 return true;
162 }
163
164 return false;
165}
166
167struct variable_validate {
168 efi_guid_t vendor;
169 char *name;
170 bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
171 unsigned long len);
172};
173
174
175
176
177
178
179
180
181
182
183
184
185static const struct variable_validate variable_validate[] = {
186 { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 },
187 { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order },
188 { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option },
189 { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order },
190 { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option },
191 { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path },
192 { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path },
193 { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path },
194 { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path },
195 { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
196 { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
197 { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
198 { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
199 { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
200 { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 },
201 { LINUX_EFI_CRASH_GUID, "*", NULL },
202 { NULL_GUID, "", NULL },
203};
204
205
206
207
208
209
210
211
212
213
214
215
216static bool
217variable_matches(const char *var_name, size_t len, const char *match_name,
218 int *match)
219{
220 for (*match = 0; ; (*match)++) {
221 char c = match_name[*match];
222
223 switch (c) {
224 case '*':
225
226 return true;
227
228 case '\0':
229
230 return (*match == len);
231
232 default:
233
234
235
236
237
238 if (*match < len && c == var_name[*match])
239 continue;
240 return false;
241 }
242 }
243}
244
245bool
246efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
247 unsigned long data_size)
248{
249 int i;
250 unsigned long utf8_size;
251 u8 *utf8_name;
252
253 utf8_size = ucs2_utf8size(var_name);
254 utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL);
255 if (!utf8_name)
256 return false;
257
258 ucs2_as_utf8(utf8_name, var_name, utf8_size);
259 utf8_name[utf8_size] = '\0';
260
261 for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
262 const char *name = variable_validate[i].name;
263 int match = 0;
264
265 if (efi_guidcmp(vendor, variable_validate[i].vendor))
266 continue;
267
268 if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
269 if (variable_validate[i].validate == NULL)
270 break;
271 kfree(utf8_name);
272 return variable_validate[i].validate(var_name, match,
273 data, data_size);
274 }
275 }
276 kfree(utf8_name);
277 return true;
278}
279EXPORT_SYMBOL_GPL(efivar_validate);
280
281bool
282efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
283 size_t len)
284{
285 int i;
286 bool found = false;
287 int match = 0;
288
289
290
291
292 for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
293 if (efi_guidcmp(variable_validate[i].vendor, vendor))
294 continue;
295
296 if (variable_matches(var_name, len,
297 variable_validate[i].name, &match)) {
298 found = true;
299 break;
300 }
301 }
302
303
304
305
306 return found;
307}
308EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
309
310static efi_status_t
311check_var_size(u32 attributes, unsigned long size)
312{
313 const struct efivar_operations *fops = __efivars->ops;
314
315 if (!fops->query_variable_store)
316 return EFI_UNSUPPORTED;
317
318 return fops->query_variable_store(attributes, size, false);
319}
320
321static efi_status_t
322check_var_size_nonblocking(u32 attributes, unsigned long size)
323{
324 const struct efivar_operations *fops = __efivars->ops;
325
326 if (!fops->query_variable_store)
327 return EFI_UNSUPPORTED;
328
329 return fops->query_variable_store(attributes, size, true);
330}
331
332static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor,
333 struct list_head *head)
334{
335 struct efivar_entry *entry, *n;
336 unsigned long strsize1, strsize2;
337 bool found = false;
338
339 strsize1 = ucs2_strsize(variable_name, 1024);
340 list_for_each_entry_safe(entry, n, head, list) {
341 strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
342 if (strsize1 == strsize2 &&
343 !memcmp(variable_name, &(entry->var.VariableName),
344 strsize2) &&
345 !efi_guidcmp(entry->var.VendorGuid,
346 *vendor)) {
347 found = true;
348 break;
349 }
350 }
351 return found;
352}
353
354
355
356
357
358
359static unsigned long var_name_strnsize(efi_char16_t *variable_name,
360 unsigned long variable_name_size)
361{
362 unsigned long len;
363 efi_char16_t c;
364
365
366
367
368
369
370 for (len = 2; len <= variable_name_size; len += sizeof(c)) {
371 c = variable_name[(len / sizeof(c)) - 1];
372 if (!c)
373 break;
374 }
375
376 return min(len, variable_name_size);
377}
378
379
380
381
382
383static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
384 unsigned long len16)
385{
386 size_t i, len8 = len16 / sizeof(efi_char16_t);
387 char *str8;
388
389
390
391
392
393
394 efivar_wq_enabled = false;
395
396 str8 = kzalloc(len8, GFP_KERNEL);
397 if (!str8)
398 return;
399
400 for (i = 0; i < len8; i++)
401 str8[i] = str16[i];
402
403 printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
404 str8, vendor_guid);
405 kfree(str8);
406}
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
422 void *data, bool duplicates, struct list_head *head)
423{
424 const struct efivar_operations *ops = __efivars->ops;
425 unsigned long variable_name_size = 1024;
426 efi_char16_t *variable_name;
427 efi_status_t status;
428 efi_guid_t vendor_guid;
429 int err = 0;
430
431 variable_name = kzalloc(variable_name_size, GFP_KERNEL);
432 if (!variable_name) {
433 printk(KERN_ERR "efivars: Memory allocation failed.\n");
434 return -ENOMEM;
435 }
436
437 spin_lock_irq(&__efivars->lock);
438
439
440
441
442
443
444 do {
445 variable_name_size = 1024;
446
447 status = ops->get_next_variable(&variable_name_size,
448 variable_name,
449 &vendor_guid);
450 switch (status) {
451 case EFI_SUCCESS:
452 if (duplicates)
453 spin_unlock_irq(&__efivars->lock);
454
455 variable_name_size = var_name_strnsize(variable_name,
456 variable_name_size);
457
458
459
460
461
462
463
464
465
466 if (duplicates &&
467 variable_is_present(variable_name, &vendor_guid,
468 head)) {
469 dup_variable_bug(variable_name, &vendor_guid,
470 variable_name_size);
471 status = EFI_NOT_FOUND;
472 } else {
473 err = func(variable_name, vendor_guid,
474 variable_name_size, data);
475 if (err)
476 status = EFI_NOT_FOUND;
477 }
478
479 if (duplicates)
480 spin_lock_irq(&__efivars->lock);
481
482 break;
483 case EFI_NOT_FOUND:
484 break;
485 default:
486 printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",
487 status);
488 status = EFI_NOT_FOUND;
489 break;
490 }
491
492 } while (status != EFI_NOT_FOUND);
493
494 spin_unlock_irq(&__efivars->lock);
495
496 kfree(variable_name);
497
498 return err;
499}
500EXPORT_SYMBOL_GPL(efivar_init);
501
502
503
504
505
506
507void efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
508{
509 spin_lock_irq(&__efivars->lock);
510 list_add(&entry->list, head);
511 spin_unlock_irq(&__efivars->lock);
512}
513EXPORT_SYMBOL_GPL(efivar_entry_add);
514
515
516
517
518
519void efivar_entry_remove(struct efivar_entry *entry)
520{
521 spin_lock_irq(&__efivars->lock);
522 list_del(&entry->list);
523 spin_unlock_irq(&__efivars->lock);
524}
525EXPORT_SYMBOL_GPL(efivar_entry_remove);
526
527
528
529
530
531
532
533
534
535
536
537
538static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
539{
540 lockdep_assert_held(&__efivars->lock);
541
542 list_del(&entry->list);
543 spin_unlock_irq(&__efivars->lock);
544}
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561int __efivar_entry_delete(struct efivar_entry *entry)
562{
563 const struct efivar_operations *ops = __efivars->ops;
564 efi_status_t status;
565
566 lockdep_assert_held(&__efivars->lock);
567
568 status = ops->set_variable(entry->var.VariableName,
569 &entry->var.VendorGuid,
570 0, 0, NULL);
571
572 return efi_status_to_err(status);
573}
574EXPORT_SYMBOL_GPL(__efivar_entry_delete);
575
576
577
578
579
580
581
582
583
584
585
586
587int efivar_entry_delete(struct efivar_entry *entry)
588{
589 const struct efivar_operations *ops = __efivars->ops;
590 efi_status_t status;
591
592 spin_lock_irq(&__efivars->lock);
593 status = ops->set_variable(entry->var.VariableName,
594 &entry->var.VendorGuid,
595 0, 0, NULL);
596 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
597 spin_unlock_irq(&__efivars->lock);
598 return efi_status_to_err(status);
599 }
600
601 efivar_entry_list_del_unlock(entry);
602 return 0;
603}
604EXPORT_SYMBOL_GPL(efivar_entry_delete);
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
628 unsigned long size, void *data, struct list_head *head)
629{
630 const struct efivar_operations *ops = __efivars->ops;
631 efi_status_t status;
632 efi_char16_t *name = entry->var.VariableName;
633 efi_guid_t vendor = entry->var.VendorGuid;
634
635 spin_lock_irq(&__efivars->lock);
636
637 if (head && efivar_entry_find(name, vendor, head, false)) {
638 spin_unlock_irq(&__efivars->lock);
639 return -EEXIST;
640 }
641
642 status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
643 if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
644 status = ops->set_variable(name, &vendor,
645 attributes, size, data);
646
647 spin_unlock_irq(&__efivars->lock);
648
649 return efi_status_to_err(status);
650
651}
652EXPORT_SYMBOL_GPL(efivar_entry_set);
653
654
655
656
657
658
659
660
661
662
663static int
664efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
665 u32 attributes, unsigned long size, void *data)
666{
667 const struct efivar_operations *ops = __efivars->ops;
668 unsigned long flags;
669 efi_status_t status;
670
671 if (!spin_trylock_irqsave(&__efivars->lock, flags))
672 return -EBUSY;
673
674 status = check_var_size_nonblocking(attributes,
675 size + ucs2_strsize(name, 1024));
676 if (status != EFI_SUCCESS) {
677 spin_unlock_irqrestore(&__efivars->lock, flags);
678 return -ENOSPC;
679 }
680
681 status = ops->set_variable_nonblocking(name, &vendor, attributes,
682 size, data);
683
684 spin_unlock_irqrestore(&__efivars->lock, flags);
685 return efi_status_to_err(status);
686}
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
706 bool block, unsigned long size, void *data)
707{
708 const struct efivar_operations *ops = __efivars->ops;
709 unsigned long flags;
710 efi_status_t status;
711
712 if (!ops->query_variable_store)
713 return -ENOSYS;
714
715
716
717
718
719
720
721
722
723
724
725 if (!block && ops->set_variable_nonblocking)
726 return efivar_entry_set_nonblocking(name, vendor, attributes,
727 size, data);
728
729 if (!block) {
730 if (!spin_trylock_irqsave(&__efivars->lock, flags))
731 return -EBUSY;
732 } else {
733 spin_lock_irqsave(&__efivars->lock, flags);
734 }
735
736 status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
737 if (status != EFI_SUCCESS) {
738 spin_unlock_irqrestore(&__efivars->lock, flags);
739 return -ENOSPC;
740 }
741
742 status = ops->set_variable(name, &vendor, attributes, size, data);
743
744 spin_unlock_irqrestore(&__efivars->lock, flags);
745
746 return efi_status_to_err(status);
747}
748EXPORT_SYMBOL_GPL(efivar_entry_set_safe);
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
768 struct list_head *head, bool remove)
769{
770 struct efivar_entry *entry, *n;
771 int strsize1, strsize2;
772 bool found = false;
773
774 lockdep_assert_held(&__efivars->lock);
775
776 list_for_each_entry_safe(entry, n, head, list) {
777 strsize1 = ucs2_strsize(name, 1024);
778 strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
779 if (strsize1 == strsize2 &&
780 !memcmp(name, &(entry->var.VariableName), strsize1) &&
781 !efi_guidcmp(guid, entry->var.VendorGuid)) {
782 found = true;
783 break;
784 }
785 }
786
787 if (!found)
788 return NULL;
789
790 if (remove) {
791 if (entry->scanning) {
792
793
794
795
796 entry->deleting = true;
797 } else
798 list_del(&entry->list);
799 }
800
801 return entry;
802}
803EXPORT_SYMBOL_GPL(efivar_entry_find);
804
805
806
807
808
809
810int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
811{
812 const struct efivar_operations *ops = __efivars->ops;
813 efi_status_t status;
814
815 *size = 0;
816
817 spin_lock_irq(&__efivars->lock);
818 status = ops->get_variable(entry->var.VariableName,
819 &entry->var.VendorGuid, NULL, size, NULL);
820 spin_unlock_irq(&__efivars->lock);
821
822 if (status != EFI_BUFFER_TOO_SMALL)
823 return efi_status_to_err(status);
824
825 return 0;
826}
827EXPORT_SYMBOL_GPL(efivar_entry_size);
828
829
830
831
832
833
834
835
836
837
838
839
840int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
841 unsigned long *size, void *data)
842{
843 const struct efivar_operations *ops = __efivars->ops;
844 efi_status_t status;
845
846 lockdep_assert_held(&__efivars->lock);
847
848 status = ops->get_variable(entry->var.VariableName,
849 &entry->var.VendorGuid,
850 attributes, size, data);
851
852 return efi_status_to_err(status);
853}
854EXPORT_SYMBOL_GPL(__efivar_entry_get);
855
856
857
858
859
860
861
862
863int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
864 unsigned long *size, void *data)
865{
866 const struct efivar_operations *ops = __efivars->ops;
867 efi_status_t status;
868
869 spin_lock_irq(&__efivars->lock);
870 status = ops->get_variable(entry->var.VariableName,
871 &entry->var.VendorGuid,
872 attributes, size, data);
873 spin_unlock_irq(&__efivars->lock);
874
875 return efi_status_to_err(status);
876}
877EXPORT_SYMBOL_GPL(efivar_entry_get);
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
902 unsigned long *size, void *data, bool *set)
903{
904 const struct efivar_operations *ops = __efivars->ops;
905 efi_char16_t *name = entry->var.VariableName;
906 efi_guid_t *vendor = &entry->var.VendorGuid;
907 efi_status_t status;
908 int err;
909
910 *set = false;
911
912 if (efivar_validate(*vendor, name, data, *size) == false)
913 return -EINVAL;
914
915
916
917
918
919
920 spin_lock_irq(&__efivars->lock);
921
922
923
924
925 status = check_var_size(attributes, *size + ucs2_strsize(name, 1024));
926 if (status != EFI_SUCCESS) {
927 if (status != EFI_UNSUPPORTED) {
928 err = efi_status_to_err(status);
929 goto out;
930 }
931
932 if (*size > 65536) {
933 err = -ENOSPC;
934 goto out;
935 }
936 }
937
938 status = ops->set_variable(name, vendor, attributes, *size, data);
939 if (status != EFI_SUCCESS) {
940 err = efi_status_to_err(status);
941 goto out;
942 }
943
944 *set = true;
945
946
947
948
949
950
951
952 *size = 0;
953 status = ops->get_variable(entry->var.VariableName,
954 &entry->var.VendorGuid,
955 NULL, size, NULL);
956
957 if (status == EFI_NOT_FOUND)
958 efivar_entry_list_del_unlock(entry);
959 else
960 spin_unlock_irq(&__efivars->lock);
961
962 if (status && status != EFI_BUFFER_TOO_SMALL)
963 return efi_status_to_err(status);
964
965 return 0;
966
967out:
968 spin_unlock_irq(&__efivars->lock);
969 return err;
970
971}
972EXPORT_SYMBOL_GPL(efivar_entry_set_get_size);
973
974
975
976
977
978
979
980
981void efivar_entry_iter_begin(void)
982{
983 spin_lock_irq(&__efivars->lock);
984}
985EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
986
987
988
989
990
991
992void efivar_entry_iter_end(void)
993{
994 spin_unlock_irq(&__efivars->lock);
995}
996EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
1021 struct list_head *head, void *data,
1022 struct efivar_entry **prev)
1023{
1024 struct efivar_entry *entry, *n;
1025 int err = 0;
1026
1027 if (!prev || !*prev) {
1028 list_for_each_entry_safe(entry, n, head, list) {
1029 err = func(entry, data);
1030 if (err)
1031 break;
1032 }
1033
1034 if (prev)
1035 *prev = entry;
1036
1037 return err;
1038 }
1039
1040
1041 list_for_each_entry_safe_continue((*prev), n, head, list) {
1042 err = func(*prev, data);
1043 if (err)
1044 break;
1045 }
1046
1047 return err;
1048}
1049EXPORT_SYMBOL_GPL(__efivar_entry_iter);
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
1066 struct list_head *head, void *data)
1067{
1068 int err = 0;
1069
1070 efivar_entry_iter_begin();
1071 err = __efivar_entry_iter(func, head, data, NULL);
1072 efivar_entry_iter_end();
1073
1074 return err;
1075}
1076EXPORT_SYMBOL_GPL(efivar_entry_iter);
1077
1078
1079
1080
1081
1082
1083
1084struct kobject *efivars_kobject(void)
1085{
1086 if (!__efivars)
1087 return NULL;
1088
1089 return __efivars->kobject;
1090}
1091EXPORT_SYMBOL_GPL(efivars_kobject);
1092
1093
1094
1095
1096void efivar_run_worker(void)
1097{
1098 if (efivar_wq_enabled)
1099 schedule_work(&efivar_work);
1100}
1101EXPORT_SYMBOL_GPL(efivar_run_worker);
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111int efivars_register(struct efivars *efivars,
1112 const struct efivar_operations *ops,
1113 struct kobject *kobject)
1114{
1115 spin_lock_init(&efivars->lock);
1116 efivars->ops = ops;
1117 efivars->kobject = kobject;
1118
1119 __efivars = efivars;
1120
1121 return 0;
1122}
1123EXPORT_SYMBOL_GPL(efivars_register);
1124
1125
1126
1127
1128
1129
1130
1131
1132int efivars_unregister(struct efivars *efivars)
1133{
1134 int rv;
1135
1136 if (!__efivars) {
1137 printk(KERN_ERR "efivars not registered\n");
1138 rv = -EINVAL;
1139 goto out;
1140 }
1141
1142 if (__efivars != efivars) {
1143 rv = -EINVAL;
1144 goto out;
1145 }
1146
1147 __efivars = NULL;
1148
1149 rv = 0;
1150out:
1151 return rv;
1152}
1153EXPORT_SYMBOL_GPL(efivars_unregister);
1154