diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 18:51:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 18:51:46 -0400 |
commit | b9394d8a657cd3c064fa432aa0905c1b58b38fe9 (patch) | |
tree | 5a0c98370f313fa11693ab72eea0dc809fd6567d /drivers | |
parent | 126de6b20bfb82cc19012d5048f11f339ae5a021 (diff) | |
parent | 7b2dd6d2c4db3912771bfcfd7ac7264011a3c831 (diff) |
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/efi changes from Peter Anvin:
"The bulk of these changes are cleaning up the efivars handling and
breaking it up into a tree of files. There are a number of fixes as
well.
The entire changeset is pretty big, but most of it is code movement.
Several of these commits are quite new; the history got very messed up
due to a mismerge with the urgent changes for rc8 which completely
broke IA64, and so Ingo requested that we rebase it to straighten it
out."
* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
efi: remove "kfree(NULL)"
efi: locking fix in efivar_entry_set_safe()
efi, pstore: Read data from variable store before memcpy()
efi, pstore: Remove entry from list when erasing
efi, pstore: Initialise 'entry' before iterating
efi: split efisubsystem from efivars
efivarfs: Move to fs/efivarfs
efivars: Move pstore code into the new EFI directory
efivars: efivar_entry API
efivars: Keep a private global pointer to efivars
efi: move utf16 string functions to efi.h
x86, efi: Make efi_memblock_x86_reserve_range more readable
efivarfs: convert to use simple_open()
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firmware/Kconfig | 37 | ||||
-rw-r--r-- | drivers/firmware/Makefile | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/Kconfig | 39 | ||||
-rw-r--r-- | drivers/firmware/efi/Makefile | 6 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-pstore.c | 251 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 134 | ||||
-rw-r--r-- | drivers/firmware/efi/efivars.c | 616 | ||||
-rw-r--r-- | drivers/firmware/efi/vars.c | 1041 | ||||
-rw-r--r-- | drivers/firmware/efivars.c | 2117 | ||||
-rw-r--r-- | drivers/firmware/google/gsmi.c | 31 |
10 files changed, 2103 insertions, 2171 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 3e532002e4d1..93876302fb2e 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig | |||
@@ -36,42 +36,6 @@ config FIRMWARE_MEMMAP | |||
36 | 36 | ||
37 | See also Documentation/ABI/testing/sysfs-firmware-memmap. | 37 | See also Documentation/ABI/testing/sysfs-firmware-memmap. |
38 | 38 | ||
39 | config EFI_VARS | ||
40 | tristate "EFI Variable Support via sysfs" | ||
41 | depends on EFI | ||
42 | select UCS2_STRING | ||
43 | default n | ||
44 | help | ||
45 | If you say Y here, you are able to get EFI (Extensible Firmware | ||
46 | Interface) variable information via sysfs. You may read, | ||
47 | write, create, and destroy EFI variables through this interface. | ||
48 | |||
49 | Note that using this driver in concert with efibootmgr requires | ||
50 | at least test release version 0.5.0-test3 or later, which is | ||
51 | available from Matt Domsch's website located at: | ||
52 | <http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz> | ||
53 | |||
54 | Subsequent efibootmgr releases may be found at: | ||
55 | <http://linux.dell.com/efibootmgr> | ||
56 | |||
57 | config EFI_VARS_PSTORE | ||
58 | bool "Register efivars backend for pstore" | ||
59 | depends on EFI_VARS && PSTORE | ||
60 | default y | ||
61 | help | ||
62 | Say Y here to enable use efivars as a backend to pstore. This | ||
63 | will allow writing console messages, crash dumps, or anything | ||
64 | else supported by pstore to EFI variables. | ||
65 | |||
66 | config EFI_VARS_PSTORE_DEFAULT_DISABLE | ||
67 | bool "Disable using efivars as a pstore backend by default" | ||
68 | depends on EFI_VARS_PSTORE | ||
69 | default n | ||
70 | help | ||
71 | Saying Y here will disable the use of efivars as a storage | ||
72 | backend for pstore by default. This setting can be overridden | ||
73 | using the efivars module's pstore_disable parameter. | ||
74 | |||
75 | config EFI_PCDP | 39 | config EFI_PCDP |
76 | bool "Console device selection via EFI PCDP or HCDP table" | 40 | bool "Console device selection via EFI PCDP or HCDP table" |
77 | depends on ACPI && EFI && IA64 | 41 | depends on ACPI && EFI && IA64 |
@@ -165,5 +129,6 @@ config ISCSI_IBFT | |||
165 | Otherwise, say N. | 129 | Otherwise, say N. |
166 | 130 | ||
167 | source "drivers/firmware/google/Kconfig" | 131 | source "drivers/firmware/google/Kconfig" |
132 | source "drivers/firmware/efi/Kconfig" | ||
168 | 133 | ||
169 | endmenu | 134 | endmenu |
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 5a7e27399729..299fad6b5867 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile | |||
@@ -4,7 +4,6 @@ | |||
4 | obj-$(CONFIG_DMI) += dmi_scan.o | 4 | obj-$(CONFIG_DMI) += dmi_scan.o |
5 | obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o | 5 | obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o |
6 | obj-$(CONFIG_EDD) += edd.o | 6 | obj-$(CONFIG_EDD) += edd.o |
7 | obj-$(CONFIG_EFI_VARS) += efivars.o | ||
8 | obj-$(CONFIG_EFI_PCDP) += pcdp.o | 7 | obj-$(CONFIG_EFI_PCDP) += pcdp.o |
9 | obj-$(CONFIG_DELL_RBU) += dell_rbu.o | 8 | obj-$(CONFIG_DELL_RBU) += dell_rbu.o |
10 | obj-$(CONFIG_DCDBAS) += dcdbas.o | 9 | obj-$(CONFIG_DCDBAS) += dcdbas.o |
@@ -14,3 +13,4 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o | |||
14 | obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o | 13 | obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o |
15 | 14 | ||
16 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ | 15 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ |
16 | obj-$(CONFIG_EFI) += efi/ | ||
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig new file mode 100644 index 000000000000..b0fc7c79dfbb --- /dev/null +++ b/drivers/firmware/efi/Kconfig | |||
@@ -0,0 +1,39 @@ | |||
1 | menu "EFI (Extensible Firmware Interface) Support" | ||
2 | depends on EFI | ||
3 | |||
4 | config EFI_VARS | ||
5 | tristate "EFI Variable Support via sysfs" | ||
6 | depends on EFI | ||
7 | default n | ||
8 | help | ||
9 | If you say Y here, you are able to get EFI (Extensible Firmware | ||
10 | Interface) variable information via sysfs. You may read, | ||
11 | write, create, and destroy EFI variables through this interface. | ||
12 | |||
13 | Note that using this driver in concert with efibootmgr requires | ||
14 | at least test release version 0.5.0-test3 or later, which is | ||
15 | available from Matt Domsch's website located at: | ||
16 | <http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz> | ||
17 | |||
18 | Subsequent efibootmgr releases may be found at: | ||
19 | <http://linux.dell.com/efibootmgr> | ||
20 | |||
21 | config EFI_VARS_PSTORE | ||
22 | tristate "Register efivars backend for pstore" | ||
23 | depends on EFI_VARS && PSTORE | ||
24 | default y | ||
25 | help | ||
26 | Say Y here to enable use efivars as a backend to pstore. This | ||
27 | will allow writing console messages, crash dumps, or anything | ||
28 | else supported by pstore to EFI variables. | ||
29 | |||
30 | config EFI_VARS_PSTORE_DEFAULT_DISABLE | ||
31 | bool "Disable using efivars as a pstore backend by default" | ||
32 | depends on EFI_VARS_PSTORE | ||
33 | default n | ||
34 | help | ||
35 | Saying Y here will disable the use of efivars as a storage | ||
36 | backend for pstore by default. This setting can be overridden | ||
37 | using the efivars module's pstore_disable parameter. | ||
38 | |||
39 | endmenu | ||
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile new file mode 100644 index 000000000000..99245ab5a79c --- /dev/null +++ b/drivers/firmware/efi/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for linux kernel | ||
3 | # | ||
4 | obj-y += efi.o vars.o | ||
5 | obj-$(CONFIG_EFI_VARS) += efivars.o | ||
6 | obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o | ||
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c new file mode 100644 index 000000000000..67615d6d038d --- /dev/null +++ b/drivers/firmware/efi/efi-pstore.c | |||
@@ -0,0 +1,251 @@ | |||
1 | #include <linux/efi.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/pstore.h> | ||
4 | #include <linux/ucs2_string.h> | ||
5 | |||
6 | #define DUMP_NAME_LEN 52 | ||
7 | |||
8 | static bool efivars_pstore_disable = | ||
9 | IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); | ||
10 | |||
11 | module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); | ||
12 | |||
13 | #define PSTORE_EFI_ATTRIBUTES \ | ||
14 | (EFI_VARIABLE_NON_VOLATILE | \ | ||
15 | EFI_VARIABLE_BOOTSERVICE_ACCESS | \ | ||
16 | EFI_VARIABLE_RUNTIME_ACCESS) | ||
17 | |||
18 | static int efi_pstore_open(struct pstore_info *psi) | ||
19 | { | ||
20 | efivar_entry_iter_begin(); | ||
21 | psi->data = NULL; | ||
22 | return 0; | ||
23 | } | ||
24 | |||
25 | static int efi_pstore_close(struct pstore_info *psi) | ||
26 | { | ||
27 | efivar_entry_iter_end(); | ||
28 | psi->data = NULL; | ||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | struct pstore_read_data { | ||
33 | u64 *id; | ||
34 | enum pstore_type_id *type; | ||
35 | int *count; | ||
36 | struct timespec *timespec; | ||
37 | char **buf; | ||
38 | }; | ||
39 | |||
40 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | ||
41 | { | ||
42 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | ||
43 | struct pstore_read_data *cb_data = data; | ||
44 | char name[DUMP_NAME_LEN]; | ||
45 | int i; | ||
46 | int cnt; | ||
47 | unsigned int part; | ||
48 | unsigned long time, size; | ||
49 | |||
50 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) | ||
51 | return 0; | ||
52 | |||
53 | for (i = 0; i < DUMP_NAME_LEN; i++) | ||
54 | name[i] = entry->var.VariableName[i]; | ||
55 | |||
56 | if (sscanf(name, "dump-type%u-%u-%d-%lu", | ||
57 | cb_data->type, &part, &cnt, &time) == 4) { | ||
58 | *cb_data->id = part; | ||
59 | *cb_data->count = cnt; | ||
60 | cb_data->timespec->tv_sec = time; | ||
61 | cb_data->timespec->tv_nsec = 0; | ||
62 | } else if (sscanf(name, "dump-type%u-%u-%lu", | ||
63 | cb_data->type, &part, &time) == 3) { | ||
64 | /* | ||
65 | * Check if an old format, | ||
66 | * which doesn't support holding | ||
67 | * multiple logs, remains. | ||
68 | */ | ||
69 | *cb_data->id = part; | ||
70 | *cb_data->count = 0; | ||
71 | cb_data->timespec->tv_sec = time; | ||
72 | cb_data->timespec->tv_nsec = 0; | ||
73 | } else | ||
74 | return 0; | ||
75 | |||
76 | entry->var.DataSize = 1024; | ||
77 | __efivar_entry_get(entry, &entry->var.Attributes, | ||
78 | &entry->var.DataSize, entry->var.Data); | ||
79 | size = entry->var.DataSize; | ||
80 | |||
81 | *cb_data->buf = kmalloc(size, GFP_KERNEL); | ||
82 | if (*cb_data->buf == NULL) | ||
83 | return -ENOMEM; | ||
84 | memcpy(*cb_data->buf, entry->var.Data, size); | ||
85 | return size; | ||
86 | } | ||
87 | |||
88 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | ||
89 | int *count, struct timespec *timespec, | ||
90 | char **buf, struct pstore_info *psi) | ||
91 | { | ||
92 | struct pstore_read_data data; | ||
93 | |||
94 | data.id = id; | ||
95 | data.type = type; | ||
96 | data.count = count; | ||
97 | data.timespec = timespec; | ||
98 | data.buf = buf; | ||
99 | |||
100 | return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data, | ||
101 | (struct efivar_entry **)&psi->data); | ||
102 | } | ||
103 | |||
104 | static int efi_pstore_write(enum pstore_type_id type, | ||
105 | enum kmsg_dump_reason reason, u64 *id, | ||
106 | unsigned int part, int count, size_t size, | ||
107 | struct pstore_info *psi) | ||
108 | { | ||
109 | char name[DUMP_NAME_LEN]; | ||
110 | efi_char16_t efi_name[DUMP_NAME_LEN]; | ||
111 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | ||
112 | int i, ret = 0; | ||
113 | |||
114 | sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, | ||
115 | get_seconds()); | ||
116 | |||
117 | for (i = 0; i < DUMP_NAME_LEN; i++) | ||
118 | efi_name[i] = name[i]; | ||
119 | |||
120 | efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, | ||
121 | !pstore_cannot_block_path(reason), | ||
122 | size, psi->buf); | ||
123 | |||
124 | if (reason == KMSG_DUMP_OOPS) | ||
125 | efivar_run_worker(); | ||
126 | |||
127 | *id = part; | ||
128 | return ret; | ||
129 | }; | ||
130 | |||
131 | struct pstore_erase_data { | ||
132 | u64 id; | ||
133 | enum pstore_type_id type; | ||
134 | int count; | ||
135 | struct timespec time; | ||
136 | efi_char16_t *name; | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Clean up an entry with the same name | ||
141 | */ | ||
142 | static int efi_pstore_erase_func(struct efivar_entry *entry, void *data) | ||
143 | { | ||
144 | struct pstore_erase_data *ed = data; | ||
145 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | ||
146 | efi_char16_t efi_name_old[DUMP_NAME_LEN]; | ||
147 | efi_char16_t *efi_name = ed->name; | ||
148 | unsigned long ucs2_len = ucs2_strlen(ed->name); | ||
149 | char name_old[DUMP_NAME_LEN]; | ||
150 | int i; | ||
151 | |||
152 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) | ||
153 | return 0; | ||
154 | |||
155 | if (ucs2_strncmp(entry->var.VariableName, | ||
156 | efi_name, (size_t)ucs2_len)) { | ||
157 | /* | ||
158 | * Check if an old format, which doesn't support | ||
159 | * holding multiple logs, remains. | ||
160 | */ | ||
161 | sprintf(name_old, "dump-type%u-%u-%lu", ed->type, | ||
162 | (unsigned int)ed->id, ed->time.tv_sec); | ||
163 | |||
164 | for (i = 0; i < DUMP_NAME_LEN; i++) | ||
165 | efi_name_old[i] = name_old[i]; | ||
166 | |||
167 | if (ucs2_strncmp(entry->var.VariableName, efi_name_old, | ||
168 | ucs2_strlen(efi_name_old))) | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /* found */ | ||
173 | __efivar_entry_delete(entry); | ||
174 | list_del(&entry->list); | ||
175 | |||
176 | return 1; | ||
177 | } | ||
178 | |||
179 | static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | ||
180 | struct timespec time, struct pstore_info *psi) | ||
181 | { | ||
182 | struct pstore_erase_data edata; | ||
183 | struct efivar_entry *entry = NULL; | ||
184 | char name[DUMP_NAME_LEN]; | ||
185 | efi_char16_t efi_name[DUMP_NAME_LEN]; | ||
186 | int found, i; | ||
187 | |||
188 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, | ||
189 | time.tv_sec); | ||
190 | |||
191 | for (i = 0; i < DUMP_NAME_LEN; i++) | ||
192 | efi_name[i] = name[i]; | ||
193 | |||
194 | edata.id = id; | ||
195 | edata.type = type; | ||
196 | edata.count = count; | ||
197 | edata.time = time; | ||
198 | edata.name = efi_name; | ||
199 | |||
200 | efivar_entry_iter_begin(); | ||
201 | found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); | ||
202 | efivar_entry_iter_end(); | ||
203 | |||
204 | if (found) | ||
205 | efivar_unregister(entry); | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static struct pstore_info efi_pstore_info = { | ||
211 | .owner = THIS_MODULE, | ||
212 | .name = "efi", | ||
213 | .open = efi_pstore_open, | ||
214 | .close = efi_pstore_close, | ||
215 | .read = efi_pstore_read, | ||
216 | .write = efi_pstore_write, | ||
217 | .erase = efi_pstore_erase, | ||
218 | }; | ||
219 | |||
220 | static __init int efivars_pstore_init(void) | ||
221 | { | ||
222 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) | ||
223 | return 0; | ||
224 | |||
225 | if (!efivars_kobject()) | ||
226 | return 0; | ||
227 | |||
228 | if (efivars_pstore_disable) | ||
229 | return 0; | ||
230 | |||
231 | efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); | ||
232 | if (!efi_pstore_info.buf) | ||
233 | return -ENOMEM; | ||
234 | |||
235 | efi_pstore_info.bufsize = 1024; | ||
236 | spin_lock_init(&efi_pstore_info.buf_lock); | ||
237 | |||
238 | pstore_register(&efi_pstore_info); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static __exit void efivars_pstore_exit(void) | ||
244 | { | ||
245 | } | ||
246 | |||
247 | module_init(efivars_pstore_init); | ||
248 | module_exit(efivars_pstore_exit); | ||
249 | |||
250 | MODULE_DESCRIPTION("EFI variable backend for pstore"); | ||
251 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c new file mode 100644 index 000000000000..5145fa344ad5 --- /dev/null +++ b/drivers/firmware/efi/efi.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * efi.c - EFI subsystem | ||
3 | * | ||
4 | * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> | ||
5 | * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> | ||
6 | * Copyright (C) 2013 Tom Gundersen <teg@jklm.no> | ||
7 | * | ||
8 | * This code registers /sys/firmware/efi{,/efivars} when EFI is supported, | ||
9 | * allowing the efivarfs to be mounted or the efivars module to be loaded. | ||
10 | * The existance of /sys/firmware/efi may also be used by userspace to | ||
11 | * determine that the system supports EFI. | ||
12 | * | ||
13 | * This file is released under the GPLv2. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kobject.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/efi.h> | ||
21 | |||
22 | static struct kobject *efi_kobj; | ||
23 | static struct kobject *efivars_kobj; | ||
24 | |||
25 | /* | ||
26 | * Let's not leave out systab information that snuck into | ||
27 | * the efivars driver | ||
28 | */ | ||
29 | static ssize_t systab_show(struct kobject *kobj, | ||
30 | struct kobj_attribute *attr, char *buf) | ||
31 | { | ||
32 | char *str = buf; | ||
33 | |||
34 | if (!kobj || !buf) | ||
35 | return -EINVAL; | ||
36 | |||
37 | if (efi.mps != EFI_INVALID_TABLE_ADDR) | ||
38 | str += sprintf(str, "MPS=0x%lx\n", efi.mps); | ||
39 | if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) | ||
40 | str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20); | ||
41 | if (efi.acpi != EFI_INVALID_TABLE_ADDR) | ||
42 | str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); | ||
43 | if (efi.smbios != EFI_INVALID_TABLE_ADDR) | ||
44 | str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); | ||
45 | if (efi.hcdp != EFI_INVALID_TABLE_ADDR) | ||
46 | str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); | ||
47 | if (efi.boot_info != EFI_INVALID_TABLE_ADDR) | ||
48 | str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info); | ||
49 | if (efi.uga != EFI_INVALID_TABLE_ADDR) | ||
50 | str += sprintf(str, "UGA=0x%lx\n", efi.uga); | ||
51 | |||
52 | return str - buf; | ||
53 | } | ||
54 | |||
55 | static struct kobj_attribute efi_attr_systab = | ||
56 | __ATTR(systab, 0400, systab_show, NULL); | ||
57 | |||
58 | static struct attribute *efi_subsys_attrs[] = { | ||
59 | &efi_attr_systab.attr, | ||
60 | NULL, /* maybe more in the future? */ | ||
61 | }; | ||
62 | |||
63 | static struct attribute_group efi_subsys_attr_group = { | ||
64 | .attrs = efi_subsys_attrs, | ||
65 | }; | ||
66 | |||
67 | static struct efivars generic_efivars; | ||
68 | static struct efivar_operations generic_ops; | ||
69 | |||
70 | static int generic_ops_register(void) | ||
71 | { | ||
72 | generic_ops.get_variable = efi.get_variable; | ||
73 | generic_ops.set_variable = efi.set_variable; | ||
74 | generic_ops.get_next_variable = efi.get_next_variable; | ||
75 | generic_ops.query_variable_store = efi_query_variable_store; | ||
76 | |||
77 | return efivars_register(&generic_efivars, &generic_ops, efi_kobj); | ||
78 | } | ||
79 | |||
80 | static void generic_ops_unregister(void) | ||
81 | { | ||
82 | efivars_unregister(&generic_efivars); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * We register the efi subsystem with the firmware subsystem and the | ||
87 | * efivars subsystem with the efi subsystem, if the system was booted with | ||
88 | * EFI. | ||
89 | */ | ||
90 | static int __init efisubsys_init(void) | ||
91 | { | ||
92 | int error; | ||
93 | |||
94 | if (!efi_enabled(EFI_BOOT)) | ||
95 | return 0; | ||
96 | |||
97 | /* We register the efi directory at /sys/firmware/efi */ | ||
98 | efi_kobj = kobject_create_and_add("efi", firmware_kobj); | ||
99 | if (!efi_kobj) { | ||
100 | pr_err("efi: Firmware registration failed.\n"); | ||
101 | return -ENOMEM; | ||
102 | } | ||
103 | |||
104 | error = generic_ops_register(); | ||
105 | if (error) | ||
106 | goto err_put; | ||
107 | |||
108 | error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); | ||
109 | if (error) { | ||
110 | pr_err("efi: Sysfs attribute export failed with error %d.\n", | ||
111 | error); | ||
112 | goto err_unregister; | ||
113 | } | ||
114 | |||
115 | /* and the standard mountpoint for efivarfs */ | ||
116 | efivars_kobj = kobject_create_and_add("efivars", efi_kobj); | ||
117 | if (!efivars_kobj) { | ||
118 | pr_err("efivars: Subsystem registration failed.\n"); | ||
119 | error = -ENOMEM; | ||
120 | goto err_remove_group; | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | |||
125 | err_remove_group: | ||
126 | sysfs_remove_group(efi_kobj, &efi_subsys_attr_group); | ||
127 | err_unregister: | ||
128 | generic_ops_unregister(); | ||
129 | err_put: | ||
130 | kobject_put(efi_kobj); | ||
131 | return error; | ||
132 | } | ||
133 | |||
134 | subsys_initcall(efisubsys_init); | ||
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c new file mode 100644 index 000000000000..5e94897244cf --- /dev/null +++ b/drivers/firmware/efi/efivars.c | |||
@@ -0,0 +1,616 @@ | |||
1 | /* | ||
2 | * Originally from efivars.c, | ||
3 | * | ||
4 | * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> | ||
5 | * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> | ||
6 | * | ||
7 | * This code takes all variables accessible from EFI runtime and | ||
8 | * exports them via sysfs | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Changelog: | ||
25 | * | ||
26 | * 17 May 2004 - Matt Domsch <Matt_Domsch@dell.com> | ||
27 | * remove check for efi_enabled in exit | ||
28 | * add MODULE_VERSION | ||
29 | * | ||
30 | * 26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com> | ||
31 | * minor bug fixes | ||
32 | * | ||
33 | * 21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com) | ||
34 | * converted driver to export variable information via sysfs | ||
35 | * and moved to drivers/firmware directory | ||
36 | * bumped revision number to v0.07 to reflect conversion & move | ||
37 | * | ||
38 | * 10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com> | ||
39 | * fix locking per Peter Chubb's findings | ||
40 | * | ||
41 | * 25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com> | ||
42 | * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse() | ||
43 | * | ||
44 | * 12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com> | ||
45 | * use list_for_each_safe when deleting vars. | ||
46 | * remove ifdef CONFIG_SMP around include <linux/smp.h> | ||
47 | * v0.04 release to linux-ia64@linuxia64.org | ||
48 | * | ||
49 | * 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
50 | * Moved vars from /proc/efi to /proc/efi/vars, and made | ||
51 | * efi.c own the /proc/efi directory. | ||
52 | * v0.03 release to linux-ia64@linuxia64.org | ||
53 | * | ||
54 | * 26 March 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
55 | * At the request of Stephane, moved ownership of /proc/efi | ||
56 | * to efi.c, and now efivars lives under /proc/efi/vars. | ||
57 | * | ||
58 | * 12 March 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
59 | * Feedback received from Stephane Eranian incorporated. | ||
60 | * efivar_write() checks copy_from_user() return value. | ||
61 | * efivar_read/write() returns proper errno. | ||
62 | * v0.02 release to linux-ia64@linuxia64.org | ||
63 | * | ||
64 | * 26 February 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
65 | * v0.01 release to linux-ia64@linuxia64.org | ||
66 | */ | ||
67 | |||
68 | #include <linux/efi.h> | ||
69 | #include <linux/module.h> | ||
70 | #include <linux/ucs2_string.h> | ||
71 | |||
72 | #define EFIVARS_VERSION "0.08" | ||
73 | #define EFIVARS_DATE "2004-May-17" | ||
74 | |||
75 | MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); | ||
76 | MODULE_DESCRIPTION("sysfs interface to EFI Variables"); | ||
77 | MODULE_LICENSE("GPL"); | ||
78 | MODULE_VERSION(EFIVARS_VERSION); | ||
79 | |||
80 | LIST_HEAD(efivar_sysfs_list); | ||
81 | EXPORT_SYMBOL_GPL(efivar_sysfs_list); | ||
82 | |||
83 | static struct kset *efivars_kset; | ||
84 | |||
85 | static struct bin_attribute *efivars_new_var; | ||
86 | static struct bin_attribute *efivars_del_var; | ||
87 | |||
88 | struct efivar_attribute { | ||
89 | struct attribute attr; | ||
90 | ssize_t (*show) (struct efivar_entry *entry, char *buf); | ||
91 | ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); | ||
92 | }; | ||
93 | |||
94 | #define EFIVAR_ATTR(_name, _mode, _show, _store) \ | ||
95 | struct efivar_attribute efivar_attr_##_name = { \ | ||
96 | .attr = {.name = __stringify(_name), .mode = _mode}, \ | ||
97 | .show = _show, \ | ||
98 | .store = _store, \ | ||
99 | }; | ||
100 | |||
101 | #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr) | ||
102 | #define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj) | ||
103 | |||
104 | /* | ||
105 | * Prototype for sysfs creation function | ||
106 | */ | ||
107 | static int | ||
108 | efivar_create_sysfs_entry(struct efivar_entry *new_var); | ||
109 | |||
110 | static ssize_t | ||
111 | efivar_guid_read(struct efivar_entry *entry, char *buf) | ||
112 | { | ||
113 | struct efi_variable *var = &entry->var; | ||
114 | char *str = buf; | ||
115 | |||
116 | if (!entry || !buf) | ||
117 | return 0; | ||
118 | |||
119 | efi_guid_unparse(&var->VendorGuid, str); | ||
120 | str += strlen(str); | ||
121 | str += sprintf(str, "\n"); | ||
122 | |||
123 | return str - buf; | ||
124 | } | ||
125 | |||
126 | static ssize_t | ||
127 | efivar_attr_read(struct efivar_entry *entry, char *buf) | ||
128 | { | ||
129 | struct efi_variable *var = &entry->var; | ||
130 | char *str = buf; | ||
131 | |||
132 | if (!entry || !buf) | ||
133 | return -EINVAL; | ||
134 | |||
135 | var->DataSize = 1024; | ||
136 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
137 | return -EIO; | ||
138 | |||
139 | if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) | ||
140 | str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n"); | ||
141 | if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) | ||
142 | str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n"); | ||
143 | if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) | ||
144 | str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n"); | ||
145 | if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) | ||
146 | str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n"); | ||
147 | if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) | ||
148 | str += sprintf(str, | ||
149 | "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n"); | ||
150 | if (var->Attributes & | ||
151 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) | ||
152 | str += sprintf(str, | ||
153 | "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n"); | ||
154 | if (var->Attributes & EFI_VARIABLE_APPEND_WRITE) | ||
155 | str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n"); | ||
156 | return str - buf; | ||
157 | } | ||
158 | |||
159 | static ssize_t | ||
160 | efivar_size_read(struct efivar_entry *entry, char *buf) | ||
161 | { | ||
162 | struct efi_variable *var = &entry->var; | ||
163 | char *str = buf; | ||
164 | |||
165 | if (!entry || !buf) | ||
166 | return -EINVAL; | ||
167 | |||
168 | var->DataSize = 1024; | ||
169 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
170 | return -EIO; | ||
171 | |||
172 | str += sprintf(str, "0x%lx\n", var->DataSize); | ||
173 | return str - buf; | ||
174 | } | ||
175 | |||
176 | static ssize_t | ||
177 | efivar_data_read(struct efivar_entry *entry, char *buf) | ||
178 | { | ||
179 | struct efi_variable *var = &entry->var; | ||
180 | |||
181 | if (!entry || !buf) | ||
182 | return -EINVAL; | ||
183 | |||
184 | var->DataSize = 1024; | ||
185 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
186 | return -EIO; | ||
187 | |||
188 | memcpy(buf, var->Data, var->DataSize); | ||
189 | return var->DataSize; | ||
190 | } | ||
191 | /* | ||
192 | * We allow each variable to be edited via rewriting the | ||
193 | * entire efi variable structure. | ||
194 | */ | ||
195 | static ssize_t | ||
196 | efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | ||
197 | { | ||
198 | struct efi_variable *new_var, *var = &entry->var; | ||
199 | int err; | ||
200 | |||
201 | if (count != sizeof(struct efi_variable)) | ||
202 | return -EINVAL; | ||
203 | |||
204 | new_var = (struct efi_variable *)buf; | ||
205 | /* | ||
206 | * If only updating the variable data, then the name | ||
207 | * and guid should remain the same | ||
208 | */ | ||
209 | if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || | ||
210 | efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { | ||
211 | printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ | ||
216 | printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
221 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { | ||
222 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | memcpy(&entry->var, new_var, count); | ||
227 | |||
228 | err = efivar_entry_set(entry, new_var->Attributes, | ||
229 | new_var->DataSize, new_var->Data, false); | ||
230 | if (err) { | ||
231 | printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); | ||
232 | return -EIO; | ||
233 | } | ||
234 | |||
235 | return count; | ||
236 | } | ||
237 | |||
238 | static ssize_t | ||
239 | efivar_show_raw(struct efivar_entry *entry, char *buf) | ||
240 | { | ||
241 | struct efi_variable *var = &entry->var; | ||
242 | |||
243 | if (!entry || !buf) | ||
244 | return 0; | ||
245 | |||
246 | var->DataSize = 1024; | ||
247 | if (efivar_entry_get(entry, &entry->var.Attributes, | ||
248 | &entry->var.DataSize, entry->var.Data)) | ||
249 | return -EIO; | ||
250 | |||
251 | memcpy(buf, var, sizeof(*var)); | ||
252 | |||
253 | return sizeof(*var); | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Generic read/write functions that call the specific functions of | ||
258 | * the attributes... | ||
259 | */ | ||
260 | static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr, | ||
261 | char *buf) | ||
262 | { | ||
263 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
264 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
265 | ssize_t ret = -EIO; | ||
266 | |||
267 | if (!capable(CAP_SYS_ADMIN)) | ||
268 | return -EACCES; | ||
269 | |||
270 | if (efivar_attr->show) { | ||
271 | ret = efivar_attr->show(var, buf); | ||
272 | } | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, | ||
277 | const char *buf, size_t count) | ||
278 | { | ||
279 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
280 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
281 | ssize_t ret = -EIO; | ||
282 | |||
283 | if (!capable(CAP_SYS_ADMIN)) | ||
284 | return -EACCES; | ||
285 | |||
286 | if (efivar_attr->store) | ||
287 | ret = efivar_attr->store(var, buf, count); | ||
288 | |||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static const struct sysfs_ops efivar_attr_ops = { | ||
293 | .show = efivar_attr_show, | ||
294 | .store = efivar_attr_store, | ||
295 | }; | ||
296 | |||
297 | static void efivar_release(struct kobject *kobj) | ||
298 | { | ||
299 | struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj); | ||
300 | kfree(var); | ||
301 | } | ||
302 | |||
303 | static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL); | ||
304 | static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL); | ||
305 | static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL); | ||
306 | static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL); | ||
307 | static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw); | ||
308 | |||
309 | static struct attribute *def_attrs[] = { | ||
310 | &efivar_attr_guid.attr, | ||
311 | &efivar_attr_size.attr, | ||
312 | &efivar_attr_attributes.attr, | ||
313 | &efivar_attr_data.attr, | ||
314 | &efivar_attr_raw_var.attr, | ||
315 | NULL, | ||
316 | }; | ||
317 | |||
318 | static struct kobj_type efivar_ktype = { | ||
319 | .release = efivar_release, | ||
320 | .sysfs_ops = &efivar_attr_ops, | ||
321 | .default_attrs = def_attrs, | ||
322 | }; | ||
323 | |||
324 | static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | ||
325 | struct bin_attribute *bin_attr, | ||
326 | char *buf, loff_t pos, size_t count) | ||
327 | { | ||
328 | struct efi_variable *new_var = (struct efi_variable *)buf; | ||
329 | struct efivar_entry *new_entry; | ||
330 | int err; | ||
331 | |||
332 | if (!capable(CAP_SYS_ADMIN)) | ||
333 | return -EACCES; | ||
334 | |||
335 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
336 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { | ||
337 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
338 | return -EINVAL; | ||
339 | } | ||
340 | |||
341 | new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); | ||
342 | if (!new_entry) | ||
343 | return -ENOMEM; | ||
344 | |||
345 | memcpy(&new_entry->var, new_var, sizeof(*new_var)); | ||
346 | |||
347 | err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, | ||
348 | new_var->Data, &efivar_sysfs_list); | ||
349 | if (err) { | ||
350 | if (err == -EEXIST) | ||
351 | err = -EINVAL; | ||
352 | goto out; | ||
353 | } | ||
354 | |||
355 | if (efivar_create_sysfs_entry(new_entry)) { | ||
356 | printk(KERN_WARNING "efivars: failed to create sysfs entry.\n"); | ||
357 | kfree(new_entry); | ||
358 | } | ||
359 | return count; | ||
360 | |||
361 | out: | ||
362 | kfree(new_entry); | ||
363 | return err; | ||
364 | } | ||
365 | |||
366 | static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | ||
367 | struct bin_attribute *bin_attr, | ||
368 | char *buf, loff_t pos, size_t count) | ||
369 | { | ||
370 | struct efi_variable *del_var = (struct efi_variable *)buf; | ||
371 | struct efivar_entry *entry; | ||
372 | int err = 0; | ||
373 | |||
374 | if (!capable(CAP_SYS_ADMIN)) | ||
375 | return -EACCES; | ||
376 | |||
377 | efivar_entry_iter_begin(); | ||
378 | entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, | ||
379 | &efivar_sysfs_list, true); | ||
380 | if (!entry) | ||
381 | err = -EINVAL; | ||
382 | else if (__efivar_entry_delete(entry)) | ||
383 | err = -EIO; | ||
384 | |||
385 | efivar_entry_iter_end(); | ||
386 | |||
387 | if (err) | ||
388 | return err; | ||
389 | |||
390 | efivar_unregister(entry); | ||
391 | |||
392 | /* It's dead Jim.... */ | ||
393 | return count; | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * efivar_create_sysfs_entry - create a new entry in sysfs | ||
398 | * @new_var: efivar entry to create | ||
399 | * | ||
400 | * Returns 1 on failure, 0 on success | ||
401 | */ | ||
402 | static int | ||
403 | efivar_create_sysfs_entry(struct efivar_entry *new_var) | ||
404 | { | ||
405 | int i, short_name_size; | ||
406 | char *short_name; | ||
407 | unsigned long variable_name_size; | ||
408 | efi_char16_t *variable_name; | ||
409 | |||
410 | variable_name = new_var->var.VariableName; | ||
411 | variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); | ||
412 | |||
413 | /* | ||
414 | * Length of the variable bytes in ASCII, plus the '-' separator, | ||
415 | * plus the GUID, plus trailing NUL | ||
416 | */ | ||
417 | short_name_size = variable_name_size / sizeof(efi_char16_t) | ||
418 | + 1 + EFI_VARIABLE_GUID_LEN + 1; | ||
419 | |||
420 | short_name = kzalloc(short_name_size, GFP_KERNEL); | ||
421 | |||
422 | if (!short_name) | ||
423 | return 1; | ||
424 | |||
425 | /* Convert Unicode to normal chars (assume top bits are 0), | ||
426 | ala UTF-8 */ | ||
427 | for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { | ||
428 | short_name[i] = variable_name[i] & 0xFF; | ||
429 | } | ||
430 | /* This is ugly, but necessary to separate one vendor's | ||
431 | private variables from another's. */ | ||
432 | |||
433 | *(short_name + strlen(short_name)) = '-'; | ||
434 | efi_guid_unparse(&new_var->var.VendorGuid, | ||
435 | short_name + strlen(short_name)); | ||
436 | |||
437 | new_var->kobj.kset = efivars_kset; | ||
438 | |||
439 | i = kobject_init_and_add(&new_var->kobj, &efivar_ktype, | ||
440 | NULL, "%s", short_name); | ||
441 | kfree(short_name); | ||
442 | if (i) | ||
443 | return 1; | ||
444 | |||
445 | kobject_uevent(&new_var->kobj, KOBJ_ADD); | ||
446 | efivar_entry_add(new_var, &efivar_sysfs_list); | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static int | ||
452 | create_efivars_bin_attributes(void) | ||
453 | { | ||
454 | struct bin_attribute *attr; | ||
455 | int error; | ||
456 | |||
457 | /* new_var */ | ||
458 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
459 | if (!attr) | ||
460 | return -ENOMEM; | ||
461 | |||
462 | attr->attr.name = "new_var"; | ||
463 | attr->attr.mode = 0200; | ||
464 | attr->write = efivar_create; | ||
465 | efivars_new_var = attr; | ||
466 | |||
467 | /* del_var */ | ||
468 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
469 | if (!attr) { | ||
470 | error = -ENOMEM; | ||
471 | goto out_free; | ||
472 | } | ||
473 | attr->attr.name = "del_var"; | ||
474 | attr->attr.mode = 0200; | ||
475 | attr->write = efivar_delete; | ||
476 | efivars_del_var = attr; | ||
477 | |||
478 | sysfs_bin_attr_init(efivars_new_var); | ||
479 | sysfs_bin_attr_init(efivars_del_var); | ||
480 | |||
481 | /* Register */ | ||
482 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
483 | if (error) { | ||
484 | printk(KERN_ERR "efivars: unable to create new_var sysfs file" | ||
485 | " due to error %d\n", error); | ||
486 | goto out_free; | ||
487 | } | ||
488 | |||
489 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var); | ||
490 | if (error) { | ||
491 | printk(KERN_ERR "efivars: unable to create del_var sysfs file" | ||
492 | " due to error %d\n", error); | ||
493 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
494 | goto out_free; | ||
495 | } | ||
496 | |||
497 | return 0; | ||
498 | out_free: | ||
499 | kfree(efivars_del_var); | ||
500 | efivars_del_var = NULL; | ||
501 | kfree(efivars_new_var); | ||
502 | efivars_new_var = NULL; | ||
503 | return error; | ||
504 | } | ||
505 | |||
506 | static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor, | ||
507 | unsigned long name_size, void *data) | ||
508 | { | ||
509 | struct efivar_entry *entry = data; | ||
510 | |||
511 | if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false)) | ||
512 | return 0; | ||
513 | |||
514 | memcpy(entry->var.VariableName, name, name_size); | ||
515 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
516 | |||
517 | return 1; | ||
518 | } | ||
519 | |||
520 | static void efivar_update_sysfs_entries(struct work_struct *work) | ||
521 | { | ||
522 | struct efivar_entry *entry; | ||
523 | int err; | ||
524 | |||
525 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
526 | if (!entry) | ||
527 | return; | ||
528 | |||
529 | /* Add new sysfs entries */ | ||
530 | while (1) { | ||
531 | memset(entry, 0, sizeof(*entry)); | ||
532 | |||
533 | err = efivar_init(efivar_update_sysfs_entry, entry, | ||
534 | true, false, &efivar_sysfs_list); | ||
535 | if (!err) | ||
536 | break; | ||
537 | |||
538 | efivar_create_sysfs_entry(entry); | ||
539 | } | ||
540 | |||
541 | kfree(entry); | ||
542 | } | ||
543 | |||
544 | static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor, | ||
545 | unsigned long name_size, void *data) | ||
546 | { | ||
547 | struct efivar_entry *entry; | ||
548 | |||
549 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
550 | if (!entry) | ||
551 | return -ENOMEM; | ||
552 | |||
553 | memcpy(entry->var.VariableName, name, name_size); | ||
554 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
555 | |||
556 | efivar_create_sysfs_entry(entry); | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) | ||
562 | { | ||
563 | efivar_entry_remove(entry); | ||
564 | efivar_unregister(entry); | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | void efivars_sysfs_exit(void) | ||
569 | { | ||
570 | /* Remove all entries and destroy */ | ||
571 | __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); | ||
572 | |||
573 | if (efivars_new_var) | ||
574 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
575 | if (efivars_del_var) | ||
576 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var); | ||
577 | kfree(efivars_new_var); | ||
578 | kfree(efivars_del_var); | ||
579 | kset_unregister(efivars_kset); | ||
580 | } | ||
581 | |||
582 | int efivars_sysfs_init(void) | ||
583 | { | ||
584 | struct kobject *parent_kobj = efivars_kobject(); | ||
585 | int error = 0; | ||
586 | |||
587 | /* No efivars has been registered yet */ | ||
588 | if (!parent_kobj) | ||
589 | return 0; | ||
590 | |||
591 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, | ||
592 | EFIVARS_DATE); | ||
593 | |||
594 | efivars_kset = kset_create_and_add("vars", NULL, parent_kobj); | ||
595 | if (!efivars_kset) { | ||
596 | printk(KERN_ERR "efivars: Subsystem registration failed.\n"); | ||
597 | return -ENOMEM; | ||
598 | } | ||
599 | |||
600 | efivar_init(efivars_sysfs_callback, NULL, false, | ||
601 | true, &efivar_sysfs_list); | ||
602 | |||
603 | error = create_efivars_bin_attributes(); | ||
604 | if (error) { | ||
605 | efivars_sysfs_exit(); | ||
606 | return error; | ||
607 | } | ||
608 | |||
609 | INIT_WORK(&efivar_work, efivar_update_sysfs_entries); | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | EXPORT_SYMBOL_GPL(efivars_sysfs_init); | ||
614 | |||
615 | module_init(efivars_sysfs_init); | ||
616 | module_exit(efivars_sysfs_exit); | ||
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c new file mode 100644 index 000000000000..391c67b182d9 --- /dev/null +++ b/drivers/firmware/efi/vars.c | |||
@@ -0,0 +1,1041 @@ | |||
1 | /* | ||
2 | * Originally from efivars.c | ||
3 | * | ||
4 | * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> | ||
5 | * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
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 | /* Private pointer to registered efivars */ | ||
38 | static struct efivars *__efivars; | ||
39 | |||
40 | static bool efivar_wq_enabled = true; | ||
41 | DECLARE_WORK(efivar_work, NULL); | ||
42 | EXPORT_SYMBOL_GPL(efivar_work); | ||
43 | |||
44 | static bool | ||
45 | validate_device_path(struct efi_variable *var, 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 | * If we're here then either node->length pointed past the end | ||
71 | * of the buffer or we reached the end of the buffer without | ||
72 | * finding a device path end node. | ||
73 | */ | ||
74 | return false; | ||
75 | } | ||
76 | |||
77 | static bool | ||
78 | validate_boot_order(struct efi_variable *var, int match, u8 *buffer, | ||
79 | unsigned long len) | ||
80 | { | ||
81 | /* An array of 16-bit integers */ | ||
82 | if ((len % 2) != 0) | ||
83 | return false; | ||
84 | |||
85 | return true; | ||
86 | } | ||
87 | |||
88 | static bool | ||
89 | validate_load_option(struct efi_variable *var, int match, u8 *buffer, | ||
90 | unsigned long len) | ||
91 | { | ||
92 | u16 filepathlength; | ||
93 | int i, desclength = 0, namelen; | ||
94 | |||
95 | namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); | ||
96 | |||
97 | /* Either "Boot" or "Driver" followed by four digits of hex */ | ||
98 | for (i = match; i < match+4; i++) { | ||
99 | if (var->VariableName[i] > 127 || | ||
100 | hex_to_bin(var->VariableName[i] & 0xff) < 0) | ||
101 | return true; | ||
102 | } | ||
103 | |||
104 | /* Reject it if there's 4 digits of hex and then further content */ | ||
105 | if (namelen > match + 4) | ||
106 | return false; | ||
107 | |||
108 | /* A valid entry must be at least 8 bytes */ | ||
109 | if (len < 8) | ||
110 | return false; | ||
111 | |||
112 | filepathlength = buffer[4] | buffer[5] << 8; | ||
113 | |||
114 | /* | ||
115 | * There's no stored length for the description, so it has to be | ||
116 | * found by hand | ||
117 | */ | ||
118 | desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; | ||
119 | |||
120 | /* Each boot entry must have a descriptor */ | ||
121 | if (!desclength) | ||
122 | return false; | ||
123 | |||
124 | /* | ||
125 | * If the sum of the length of the description, the claimed filepath | ||
126 | * length and the original header are greater than the length of the | ||
127 | * variable, it's malformed | ||
128 | */ | ||
129 | if ((desclength + filepathlength + 6) > len) | ||
130 | return false; | ||
131 | |||
132 | /* | ||
133 | * And, finally, check the filepath | ||
134 | */ | ||
135 | return validate_device_path(var, match, buffer + desclength + 6, | ||
136 | filepathlength); | ||
137 | } | ||
138 | |||
139 | static bool | ||
140 | validate_uint16(struct efi_variable *var, int match, u8 *buffer, | ||
141 | unsigned long len) | ||
142 | { | ||
143 | /* A single 16-bit integer */ | ||
144 | if (len != 2) | ||
145 | return false; | ||
146 | |||
147 | return true; | ||
148 | } | ||
149 | |||
150 | static bool | ||
151 | validate_ascii_string(struct efi_variable *var, 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 | |||
167 | struct variable_validate { | ||
168 | char *name; | ||
169 | bool (*validate)(struct efi_variable *var, int match, u8 *data, | ||
170 | unsigned long len); | ||
171 | }; | ||
172 | |||
173 | static const struct variable_validate variable_validate[] = { | ||
174 | { "BootNext", validate_uint16 }, | ||
175 | { "BootOrder", validate_boot_order }, | ||
176 | { "DriverOrder", validate_boot_order }, | ||
177 | { "Boot*", validate_load_option }, | ||
178 | { "Driver*", validate_load_option }, | ||
179 | { "ConIn", validate_device_path }, | ||
180 | { "ConInDev", validate_device_path }, | ||
181 | { "ConOut", validate_device_path }, | ||
182 | { "ConOutDev", validate_device_path }, | ||
183 | { "ErrOut", validate_device_path }, | ||
184 | { "ErrOutDev", validate_device_path }, | ||
185 | { "Timeout", validate_uint16 }, | ||
186 | { "Lang", validate_ascii_string }, | ||
187 | { "PlatformLang", validate_ascii_string }, | ||
188 | { "", NULL }, | ||
189 | }; | ||
190 | |||
191 | bool | ||
192 | efivar_validate(struct efi_variable *var, u8 *data, unsigned long len) | ||
193 | { | ||
194 | int i; | ||
195 | u16 *unicode_name = var->VariableName; | ||
196 | |||
197 | for (i = 0; variable_validate[i].validate != NULL; i++) { | ||
198 | const char *name = variable_validate[i].name; | ||
199 | int match; | ||
200 | |||
201 | for (match = 0; ; match++) { | ||
202 | char c = name[match]; | ||
203 | u16 u = unicode_name[match]; | ||
204 | |||
205 | /* All special variables are plain ascii */ | ||
206 | if (u > 127) | ||
207 | return true; | ||
208 | |||
209 | /* Wildcard in the matching name means we've matched */ | ||
210 | if (c == '*') | ||
211 | return variable_validate[i].validate(var, | ||
212 | match, data, len); | ||
213 | |||
214 | /* Case sensitive match */ | ||
215 | if (c != u) | ||
216 | break; | ||
217 | |||
218 | /* Reached the end of the string while matching */ | ||
219 | if (!c) | ||
220 | return variable_validate[i].validate(var, | ||
221 | match, data, len); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return true; | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(efivar_validate); | ||
228 | |||
229 | static efi_status_t | ||
230 | check_var_size(u32 attributes, unsigned long size) | ||
231 | { | ||
232 | const struct efivar_operations *fops = __efivars->ops; | ||
233 | |||
234 | if (!fops->query_variable_store) | ||
235 | return EFI_UNSUPPORTED; | ||
236 | |||
237 | return fops->query_variable_store(attributes, size); | ||
238 | } | ||
239 | |||
240 | static int efi_status_to_err(efi_status_t status) | ||
241 | { | ||
242 | int err; | ||
243 | |||
244 | switch (status) { | ||
245 | case EFI_SUCCESS: | ||
246 | err = 0; | ||
247 | break; | ||
248 | case EFI_INVALID_PARAMETER: | ||
249 | err = -EINVAL; | ||
250 | break; | ||
251 | case EFI_OUT_OF_RESOURCES: | ||
252 | err = -ENOSPC; | ||
253 | break; | ||
254 | case EFI_DEVICE_ERROR: | ||
255 | err = -EIO; | ||
256 | break; | ||
257 | case EFI_WRITE_PROTECTED: | ||
258 | err = -EROFS; | ||
259 | break; | ||
260 | case EFI_SECURITY_VIOLATION: | ||
261 | err = -EACCES; | ||
262 | break; | ||
263 | case EFI_NOT_FOUND: | ||
264 | err = -ENOENT; | ||
265 | break; | ||
266 | default: | ||
267 | err = -EINVAL; | ||
268 | } | ||
269 | |||
270 | return err; | ||
271 | } | ||
272 | |||
273 | static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor, | ||
274 | struct list_head *head) | ||
275 | { | ||
276 | struct efivar_entry *entry, *n; | ||
277 | unsigned long strsize1, strsize2; | ||
278 | bool found = false; | ||
279 | |||
280 | strsize1 = ucs2_strsize(variable_name, 1024); | ||
281 | list_for_each_entry_safe(entry, n, head, list) { | ||
282 | strsize2 = ucs2_strsize(entry->var.VariableName, 1024); | ||
283 | if (strsize1 == strsize2 && | ||
284 | !memcmp(variable_name, &(entry->var.VariableName), | ||
285 | strsize2) && | ||
286 | !efi_guidcmp(entry->var.VendorGuid, | ||
287 | *vendor)) { | ||
288 | found = true; | ||
289 | break; | ||
290 | } | ||
291 | } | ||
292 | return found; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Returns the size of variable_name, in bytes, including the | ||
297 | * terminating NULL character, or variable_name_size if no NULL | ||
298 | * character is found among the first variable_name_size bytes. | ||
299 | */ | ||
300 | static unsigned long var_name_strnsize(efi_char16_t *variable_name, | ||
301 | unsigned long variable_name_size) | ||
302 | { | ||
303 | unsigned long len; | ||
304 | efi_char16_t c; | ||
305 | |||
306 | /* | ||
307 | * The variable name is, by definition, a NULL-terminated | ||
308 | * string, so make absolutely sure that variable_name_size is | ||
309 | * the value we expect it to be. If not, return the real size. | ||
310 | */ | ||
311 | for (len = 2; len <= variable_name_size; len += sizeof(c)) { | ||
312 | c = variable_name[(len / sizeof(c)) - 1]; | ||
313 | if (!c) | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | return min(len, variable_name_size); | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * Print a warning when duplicate EFI variables are encountered and | ||
322 | * disable the sysfs workqueue since the firmware is buggy. | ||
323 | */ | ||
324 | static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | ||
325 | unsigned long len16) | ||
326 | { | ||
327 | size_t i, len8 = len16 / sizeof(efi_char16_t); | ||
328 | char *s8; | ||
329 | |||
330 | /* | ||
331 | * Disable the workqueue since the algorithm it uses for | ||
332 | * detecting new variables won't work with this buggy | ||
333 | * implementation of GetNextVariableName(). | ||
334 | */ | ||
335 | efivar_wq_enabled = false; | ||
336 | |||
337 | s8 = kzalloc(len8, GFP_KERNEL); | ||
338 | if (!s8) | ||
339 | return; | ||
340 | |||
341 | for (i = 0; i < len8; i++) | ||
342 | s8[i] = s16[i]; | ||
343 | |||
344 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", | ||
345 | s8, vendor_guid); | ||
346 | kfree(s8); | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * efivar_init - build the initial list of EFI variables | ||
351 | * @func: callback function to invoke for every variable | ||
352 | * @data: function-specific data to pass to @func | ||
353 | * @atomic: do we need to execute the @func-loop atomically? | ||
354 | * @duplicates: error if we encounter duplicates on @head? | ||
355 | * @head: initialised head of variable list | ||
356 | * | ||
357 | * Get every EFI variable from the firmware and invoke @func. @func | ||
358 | * should call efivar_entry_add() to build the list of variables. | ||
359 | * | ||
360 | * Returns 0 on success, or a kernel error code on failure. | ||
361 | */ | ||
362 | int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), | ||
363 | void *data, bool atomic, bool duplicates, | ||
364 | struct list_head *head) | ||
365 | { | ||
366 | const struct efivar_operations *ops = __efivars->ops; | ||
367 | unsigned long variable_name_size = 1024; | ||
368 | efi_char16_t *variable_name; | ||
369 | efi_status_t status; | ||
370 | efi_guid_t vendor_guid; | ||
371 | int err = 0; | ||
372 | |||
373 | variable_name = kzalloc(variable_name_size, GFP_KERNEL); | ||
374 | if (!variable_name) { | ||
375 | printk(KERN_ERR "efivars: Memory allocation failed.\n"); | ||
376 | return -ENOMEM; | ||
377 | } | ||
378 | |||
379 | spin_lock_irq(&__efivars->lock); | ||
380 | |||
381 | /* | ||
382 | * Per EFI spec, the maximum storage allocated for both | ||
383 | * the variable name and variable data is 1024 bytes. | ||
384 | */ | ||
385 | |||
386 | do { | ||
387 | variable_name_size = 1024; | ||
388 | |||
389 | status = ops->get_next_variable(&variable_name_size, | ||
390 | variable_name, | ||
391 | &vendor_guid); | ||
392 | switch (status) { | ||
393 | case EFI_SUCCESS: | ||
394 | if (!atomic) | ||
395 | spin_unlock_irq(&__efivars->lock); | ||
396 | |||
397 | variable_name_size = var_name_strnsize(variable_name, | ||
398 | variable_name_size); | ||
399 | |||
400 | /* | ||
401 | * Some firmware implementations return the | ||
402 | * same variable name on multiple calls to | ||
403 | * get_next_variable(). Terminate the loop | ||
404 | * immediately as there is no guarantee that | ||
405 | * we'll ever see a different variable name, | ||
406 | * and may end up looping here forever. | ||
407 | */ | ||
408 | if (duplicates && | ||
409 | variable_is_present(variable_name, &vendor_guid, head)) { | ||
410 | dup_variable_bug(variable_name, &vendor_guid, | ||
411 | variable_name_size); | ||
412 | if (!atomic) | ||
413 | spin_lock_irq(&__efivars->lock); | ||
414 | |||
415 | status = EFI_NOT_FOUND; | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | err = func(variable_name, vendor_guid, variable_name_size, data); | ||
420 | if (err) | ||
421 | status = EFI_NOT_FOUND; | ||
422 | |||
423 | if (!atomic) | ||
424 | spin_lock_irq(&__efivars->lock); | ||
425 | |||
426 | break; | ||
427 | case EFI_NOT_FOUND: | ||
428 | break; | ||
429 | default: | ||
430 | printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n", | ||
431 | status); | ||
432 | status = EFI_NOT_FOUND; | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | } while (status != EFI_NOT_FOUND); | ||
437 | |||
438 | spin_unlock_irq(&__efivars->lock); | ||
439 | |||
440 | kfree(variable_name); | ||
441 | |||
442 | return err; | ||
443 | } | ||
444 | EXPORT_SYMBOL_GPL(efivar_init); | ||
445 | |||
446 | /** | ||
447 | * efivar_entry_add - add entry to variable list | ||
448 | * @entry: entry to add to list | ||
449 | * @head: list head | ||
450 | */ | ||
451 | void efivar_entry_add(struct efivar_entry *entry, struct list_head *head) | ||
452 | { | ||
453 | spin_lock_irq(&__efivars->lock); | ||
454 | list_add(&entry->list, head); | ||
455 | spin_unlock_irq(&__efivars->lock); | ||
456 | } | ||
457 | EXPORT_SYMBOL_GPL(efivar_entry_add); | ||
458 | |||
459 | /** | ||
460 | * efivar_entry_remove - remove entry from variable list | ||
461 | * @entry: entry to remove from list | ||
462 | */ | ||
463 | void efivar_entry_remove(struct efivar_entry *entry) | ||
464 | { | ||
465 | spin_lock_irq(&__efivars->lock); | ||
466 | list_del(&entry->list); | ||
467 | spin_unlock_irq(&__efivars->lock); | ||
468 | } | ||
469 | EXPORT_SYMBOL_GPL(efivar_entry_remove); | ||
470 | |||
471 | /* | ||
472 | * efivar_entry_list_del_unlock - remove entry from variable list | ||
473 | * @entry: entry to remove | ||
474 | * | ||
475 | * Remove @entry from the variable list and release the list lock. | ||
476 | * | ||
477 | * NOTE: slightly weird locking semantics here - we expect to be | ||
478 | * called with the efivars lock already held, and we release it before | ||
479 | * returning. This is because this function is usually called after | ||
480 | * set_variable() while the lock is still held. | ||
481 | */ | ||
482 | static void efivar_entry_list_del_unlock(struct efivar_entry *entry) | ||
483 | { | ||
484 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
485 | |||
486 | list_del(&entry->list); | ||
487 | spin_unlock_irq(&__efivars->lock); | ||
488 | } | ||
489 | |||
490 | /** | ||
491 | * __efivar_entry_delete - delete an EFI variable | ||
492 | * @entry: entry containing EFI variable to delete | ||
493 | * | ||
494 | * Delete the variable from the firmware but leave @entry on the | ||
495 | * variable list. | ||
496 | * | ||
497 | * This function differs from efivar_entry_delete() because it does | ||
498 | * not remove @entry from the variable list. Also, it is safe to be | ||
499 | * called from within a efivar_entry_iter_begin() and | ||
500 | * efivar_entry_iter_end() region, unlike efivar_entry_delete(). | ||
501 | * | ||
502 | * Returns 0 on success, or a converted EFI status code if | ||
503 | * set_variable() fails. | ||
504 | */ | ||
505 | int __efivar_entry_delete(struct efivar_entry *entry) | ||
506 | { | ||
507 | const struct efivar_operations *ops = __efivars->ops; | ||
508 | efi_status_t status; | ||
509 | |||
510 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
511 | |||
512 | status = ops->set_variable(entry->var.VariableName, | ||
513 | &entry->var.VendorGuid, | ||
514 | 0, 0, NULL); | ||
515 | |||
516 | return efi_status_to_err(status); | ||
517 | } | ||
518 | EXPORT_SYMBOL_GPL(__efivar_entry_delete); | ||
519 | |||
520 | /** | ||
521 | * efivar_entry_delete - delete variable and remove entry from list | ||
522 | * @entry: entry containing variable to delete | ||
523 | * | ||
524 | * Delete the variable from the firmware and remove @entry from the | ||
525 | * variable list. It is the caller's responsibility to free @entry | ||
526 | * once we return. | ||
527 | * | ||
528 | * Returns 0 on success, or a converted EFI status code if | ||
529 | * set_variable() fails. | ||
530 | */ | ||
531 | int efivar_entry_delete(struct efivar_entry *entry) | ||
532 | { | ||
533 | const struct efivar_operations *ops = __efivars->ops; | ||
534 | efi_status_t status; | ||
535 | |||
536 | spin_lock_irq(&__efivars->lock); | ||
537 | status = ops->set_variable(entry->var.VariableName, | ||
538 | &entry->var.VendorGuid, | ||
539 | 0, 0, NULL); | ||
540 | if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { | ||
541 | spin_unlock_irq(&__efivars->lock); | ||
542 | return efi_status_to_err(status); | ||
543 | } | ||
544 | |||
545 | efivar_entry_list_del_unlock(entry); | ||
546 | return 0; | ||
547 | } | ||
548 | EXPORT_SYMBOL_GPL(efivar_entry_delete); | ||
549 | |||
550 | /** | ||
551 | * efivar_entry_set - call set_variable() | ||
552 | * @entry: entry containing the EFI variable to write | ||
553 | * @attributes: variable attributes | ||
554 | * @size: size of @data buffer | ||
555 | * @data: buffer containing variable data | ||
556 | * @head: head of variable list | ||
557 | * | ||
558 | * Calls set_variable() for an EFI variable. If creating a new EFI | ||
559 | * variable, this function is usually followed by efivar_entry_add(). | ||
560 | * | ||
561 | * Before writing the variable, the remaining EFI variable storage | ||
562 | * space is checked to ensure there is enough room available. | ||
563 | * | ||
564 | * If @head is not NULL a lookup is performed to determine whether | ||
565 | * the entry is already on the list. | ||
566 | * | ||
567 | * Returns 0 on success, -EEXIST if a lookup is performed and the entry | ||
568 | * already exists on the list, or a converted EFI status code if | ||
569 | * set_variable() fails. | ||
570 | */ | ||
571 | int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | ||
572 | unsigned long size, void *data, struct list_head *head) | ||
573 | { | ||
574 | const struct efivar_operations *ops = __efivars->ops; | ||
575 | efi_status_t status; | ||
576 | efi_char16_t *name = entry->var.VariableName; | ||
577 | efi_guid_t vendor = entry->var.VendorGuid; | ||
578 | |||
579 | spin_lock_irq(&__efivars->lock); | ||
580 | |||
581 | if (head && efivar_entry_find(name, vendor, head, false)) { | ||
582 | spin_unlock_irq(&__efivars->lock); | ||
583 | return -EEXIST; | ||
584 | } | ||
585 | |||
586 | status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); | ||
587 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) | ||
588 | status = ops->set_variable(name, &vendor, | ||
589 | attributes, size, data); | ||
590 | |||
591 | spin_unlock_irq(&__efivars->lock); | ||
592 | |||
593 | return efi_status_to_err(status); | ||
594 | |||
595 | } | ||
596 | EXPORT_SYMBOL_GPL(efivar_entry_set); | ||
597 | |||
598 | /** | ||
599 | * efivar_entry_set_safe - call set_variable() if enough space in firmware | ||
600 | * @name: buffer containing the variable name | ||
601 | * @vendor: variable vendor guid | ||
602 | * @attributes: variable attributes | ||
603 | * @block: can we block in this context? | ||
604 | * @size: size of @data buffer | ||
605 | * @data: buffer containing variable data | ||
606 | * | ||
607 | * Ensures there is enough free storage in the firmware for this variable, and | ||
608 | * if so, calls set_variable(). If creating a new EFI variable, this function | ||
609 | * is usually followed by efivar_entry_add(). | ||
610 | * | ||
611 | * Returns 0 on success, -ENOSPC if the firmware does not have enough | ||
612 | * space for set_variable() to succeed, or a converted EFI status code | ||
613 | * if set_variable() fails. | ||
614 | */ | ||
615 | int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | ||
616 | bool block, unsigned long size, void *data) | ||
617 | { | ||
618 | const struct efivar_operations *ops = __efivars->ops; | ||
619 | unsigned long flags; | ||
620 | efi_status_t status; | ||
621 | |||
622 | if (!ops->query_variable_store) | ||
623 | return -ENOSYS; | ||
624 | |||
625 | if (!block) { | ||
626 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | ||
627 | return -EBUSY; | ||
628 | } else { | ||
629 | spin_lock_irqsave(&__efivars->lock, flags); | ||
630 | } | ||
631 | |||
632 | status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); | ||
633 | if (status != EFI_SUCCESS) { | ||
634 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
635 | return -ENOSPC; | ||
636 | } | ||
637 | |||
638 | status = ops->set_variable(name, &vendor, attributes, size, data); | ||
639 | |||
640 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
641 | |||
642 | return efi_status_to_err(status); | ||
643 | } | ||
644 | EXPORT_SYMBOL_GPL(efivar_entry_set_safe); | ||
645 | |||
646 | /** | ||
647 | * efivar_entry_find - search for an entry | ||
648 | * @name: the EFI variable name | ||
649 | * @guid: the EFI variable vendor's guid | ||
650 | * @head: head of the variable list | ||
651 | * @remove: should we remove the entry from the list? | ||
652 | * | ||
653 | * Search for an entry on the variable list that has the EFI variable | ||
654 | * name @name and vendor guid @guid. If an entry is found on the list | ||
655 | * and @remove is true, the entry is removed from the list. | ||
656 | * | ||
657 | * The caller MUST call efivar_entry_iter_begin() and | ||
658 | * efivar_entry_iter_end() before and after the invocation of this | ||
659 | * function, respectively. | ||
660 | * | ||
661 | * Returns the entry if found on the list, %NULL otherwise. | ||
662 | */ | ||
663 | struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, | ||
664 | struct list_head *head, bool remove) | ||
665 | { | ||
666 | struct efivar_entry *entry, *n; | ||
667 | int strsize1, strsize2; | ||
668 | bool found = false; | ||
669 | |||
670 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
671 | |||
672 | list_for_each_entry_safe(entry, n, head, list) { | ||
673 | strsize1 = ucs2_strsize(name, 1024); | ||
674 | strsize2 = ucs2_strsize(entry->var.VariableName, 1024); | ||
675 | if (strsize1 == strsize2 && | ||
676 | !memcmp(name, &(entry->var.VariableName), strsize1) && | ||
677 | !efi_guidcmp(guid, entry->var.VendorGuid)) { | ||
678 | found = true; | ||
679 | break; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | if (!found) | ||
684 | return NULL; | ||
685 | |||
686 | if (remove) | ||
687 | list_del(&entry->list); | ||
688 | |||
689 | return entry; | ||
690 | } | ||
691 | EXPORT_SYMBOL_GPL(efivar_entry_find); | ||
692 | |||
693 | /** | ||
694 | * efivar_entry_size - obtain the size of a variable | ||
695 | * @entry: entry for this variable | ||
696 | * @size: location to store the variable's size | ||
697 | */ | ||
698 | int efivar_entry_size(struct efivar_entry *entry, unsigned long *size) | ||
699 | { | ||
700 | const struct efivar_operations *ops = __efivars->ops; | ||
701 | efi_status_t status; | ||
702 | |||
703 | *size = 0; | ||
704 | |||
705 | spin_lock_irq(&__efivars->lock); | ||
706 | status = ops->get_variable(entry->var.VariableName, | ||
707 | &entry->var.VendorGuid, NULL, size, NULL); | ||
708 | spin_unlock_irq(&__efivars->lock); | ||
709 | |||
710 | if (status != EFI_BUFFER_TOO_SMALL) | ||
711 | return efi_status_to_err(status); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | EXPORT_SYMBOL_GPL(efivar_entry_size); | ||
716 | |||
717 | /** | ||
718 | * __efivar_entry_get - call get_variable() | ||
719 | * @entry: read data for this variable | ||
720 | * @attributes: variable attributes | ||
721 | * @size: size of @data buffer | ||
722 | * @data: buffer to store variable data | ||
723 | * | ||
724 | * The caller MUST call efivar_entry_iter_begin() and | ||
725 | * efivar_entry_iter_end() before and after the invocation of this | ||
726 | * function, respectively. | ||
727 | */ | ||
728 | int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, | ||
729 | unsigned long *size, void *data) | ||
730 | { | ||
731 | const struct efivar_operations *ops = __efivars->ops; | ||
732 | efi_status_t status; | ||
733 | |||
734 | WARN_ON(!spin_is_locked(&__efivars->lock)); | ||
735 | |||
736 | status = ops->get_variable(entry->var.VariableName, | ||
737 | &entry->var.VendorGuid, | ||
738 | attributes, size, data); | ||
739 | |||
740 | return efi_status_to_err(status); | ||
741 | } | ||
742 | EXPORT_SYMBOL_GPL(__efivar_entry_get); | ||
743 | |||
744 | /** | ||
745 | * efivar_entry_get - call get_variable() | ||
746 | * @entry: read data for this variable | ||
747 | * @attributes: variable attributes | ||
748 | * @size: size of @data buffer | ||
749 | * @data: buffer to store variable data | ||
750 | */ | ||
751 | int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, | ||
752 | unsigned long *size, void *data) | ||
753 | { | ||
754 | const struct efivar_operations *ops = __efivars->ops; | ||
755 | efi_status_t status; | ||
756 | |||
757 | spin_lock_irq(&__efivars->lock); | ||
758 | status = ops->get_variable(entry->var.VariableName, | ||
759 | &entry->var.VendorGuid, | ||
760 | attributes, size, data); | ||
761 | spin_unlock_irq(&__efivars->lock); | ||
762 | |||
763 | return efi_status_to_err(status); | ||
764 | } | ||
765 | EXPORT_SYMBOL_GPL(efivar_entry_get); | ||
766 | |||
767 | /** | ||
768 | * efivar_entry_set_get_size - call set_variable() and get new size (atomic) | ||
769 | * @entry: entry containing variable to set and get | ||
770 | * @attributes: attributes of variable to be written | ||
771 | * @size: size of data buffer | ||
772 | * @data: buffer containing data to write | ||
773 | * @set: did the set_variable() call succeed? | ||
774 | * | ||
775 | * This is a pretty special (complex) function. See efivarfs_file_write(). | ||
776 | * | ||
777 | * Atomically call set_variable() for @entry and if the call is | ||
778 | * successful, return the new size of the variable from get_variable() | ||
779 | * in @size. The success of set_variable() is indicated by @set. | ||
780 | * | ||
781 | * Returns 0 on success, -EINVAL if the variable data is invalid, | ||
782 | * -ENOSPC if the firmware does not have enough available space, or a | ||
783 | * converted EFI status code if either of set_variable() or | ||
784 | * get_variable() fail. | ||
785 | * | ||
786 | * If the EFI variable does not exist when calling set_variable() | ||
787 | * (EFI_NOT_FOUND), @entry is removed from the variable list. | ||
788 | */ | ||
789 | int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, | ||
790 | unsigned long *size, void *data, bool *set) | ||
791 | { | ||
792 | const struct efivar_operations *ops = __efivars->ops; | ||
793 | efi_char16_t *name = entry->var.VariableName; | ||
794 | efi_guid_t *vendor = &entry->var.VendorGuid; | ||
795 | efi_status_t status; | ||
796 | int err; | ||
797 | |||
798 | *set = false; | ||
799 | |||
800 | if (efivar_validate(&entry->var, data, *size) == false) | ||
801 | return -EINVAL; | ||
802 | |||
803 | /* | ||
804 | * The lock here protects the get_variable call, the conditional | ||
805 | * set_variable call, and removal of the variable from the efivars | ||
806 | * list (in the case of an authenticated delete). | ||
807 | */ | ||
808 | spin_lock_irq(&__efivars->lock); | ||
809 | |||
810 | /* | ||
811 | * Ensure that the available space hasn't shrunk below the safe level | ||
812 | */ | ||
813 | status = check_var_size(attributes, *size + ucs2_strsize(name, 1024)); | ||
814 | if (status != EFI_SUCCESS) { | ||
815 | if (status != EFI_UNSUPPORTED) { | ||
816 | err = efi_status_to_err(status); | ||
817 | goto out; | ||
818 | } | ||
819 | |||
820 | if (*size > 65536) { | ||
821 | err = -ENOSPC; | ||
822 | goto out; | ||
823 | } | ||
824 | } | ||
825 | |||
826 | status = ops->set_variable(name, vendor, attributes, *size, data); | ||
827 | if (status != EFI_SUCCESS) { | ||
828 | err = efi_status_to_err(status); | ||
829 | goto out; | ||
830 | } | ||
831 | |||
832 | *set = true; | ||
833 | |||
834 | /* | ||
835 | * Writing to the variable may have caused a change in size (which | ||
836 | * could either be an append or an overwrite), or the variable to be | ||
837 | * deleted. Perform a GetVariable() so we can tell what actually | ||
838 | * happened. | ||
839 | */ | ||
840 | *size = 0; | ||
841 | status = ops->get_variable(entry->var.VariableName, | ||
842 | &entry->var.VendorGuid, | ||
843 | NULL, size, NULL); | ||
844 | |||
845 | if (status == EFI_NOT_FOUND) | ||
846 | efivar_entry_list_del_unlock(entry); | ||
847 | else | ||
848 | spin_unlock_irq(&__efivars->lock); | ||
849 | |||
850 | if (status && status != EFI_BUFFER_TOO_SMALL) | ||
851 | return efi_status_to_err(status); | ||
852 | |||
853 | return 0; | ||
854 | |||
855 | out: | ||
856 | spin_unlock_irq(&__efivars->lock); | ||
857 | return err; | ||
858 | |||
859 | } | ||
860 | EXPORT_SYMBOL_GPL(efivar_entry_set_get_size); | ||
861 | |||
862 | /** | ||
863 | * efivar_entry_iter_begin - begin iterating the variable list | ||
864 | * | ||
865 | * Lock the variable list to prevent entry insertion and removal until | ||
866 | * efivar_entry_iter_end() is called. This function is usually used in | ||
867 | * conjunction with __efivar_entry_iter() or efivar_entry_iter(). | ||
868 | */ | ||
869 | void efivar_entry_iter_begin(void) | ||
870 | { | ||
871 | spin_lock_irq(&__efivars->lock); | ||
872 | } | ||
873 | EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); | ||
874 | |||
875 | /** | ||
876 | * efivar_entry_iter_end - finish iterating the variable list | ||
877 | * | ||
878 | * Unlock the variable list and allow modifications to the list again. | ||
879 | */ | ||
880 | void efivar_entry_iter_end(void) | ||
881 | { | ||
882 | spin_unlock_irq(&__efivars->lock); | ||
883 | } | ||
884 | EXPORT_SYMBOL_GPL(efivar_entry_iter_end); | ||
885 | |||
886 | /** | ||
887 | * __efivar_entry_iter - iterate over variable list | ||
888 | * @func: callback function | ||
889 | * @head: head of the variable list | ||
890 | * @data: function-specific data to pass to callback | ||
891 | * @prev: entry to begin iterating from | ||
892 | * | ||
893 | * Iterate over the list of EFI variables and call @func with every | ||
894 | * entry on the list. It is safe for @func to remove entries in the | ||
895 | * list via efivar_entry_delete(). | ||
896 | * | ||
897 | * You MUST call efivar_enter_iter_begin() before this function, and | ||
898 | * efivar_entry_iter_end() afterwards. | ||
899 | * | ||
900 | * It is possible to begin iteration from an arbitrary entry within | ||
901 | * the list by passing @prev. @prev is updated on return to point to | ||
902 | * the last entry passed to @func. To begin iterating from the | ||
903 | * beginning of the list @prev must be %NULL. | ||
904 | * | ||
905 | * The restrictions for @func are the same as documented for | ||
906 | * efivar_entry_iter(). | ||
907 | */ | ||
908 | int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *), | ||
909 | struct list_head *head, void *data, | ||
910 | struct efivar_entry **prev) | ||
911 | { | ||
912 | struct efivar_entry *entry, *n; | ||
913 | int err = 0; | ||
914 | |||
915 | if (!prev || !*prev) { | ||
916 | list_for_each_entry_safe(entry, n, head, list) { | ||
917 | err = func(entry, data); | ||
918 | if (err) | ||
919 | break; | ||
920 | } | ||
921 | |||
922 | if (prev) | ||
923 | *prev = entry; | ||
924 | |||
925 | return err; | ||
926 | } | ||
927 | |||
928 | |||
929 | list_for_each_entry_safe_continue((*prev), n, head, list) { | ||
930 | err = func(*prev, data); | ||
931 | if (err) | ||
932 | break; | ||
933 | } | ||
934 | |||
935 | return err; | ||
936 | } | ||
937 | EXPORT_SYMBOL_GPL(__efivar_entry_iter); | ||
938 | |||
939 | /** | ||
940 | * efivar_entry_iter - iterate over variable list | ||
941 | * @func: callback function | ||
942 | * @head: head of variable list | ||
943 | * @data: function-specific data to pass to callback | ||
944 | * | ||
945 | * Iterate over the list of EFI variables and call @func with every | ||
946 | * entry on the list. It is safe for @func to remove entries in the | ||
947 | * list via efivar_entry_delete() while iterating. | ||
948 | * | ||
949 | * Some notes for the callback function: | ||
950 | * - a non-zero return value indicates an error and terminates the loop | ||
951 | * - @func is called from atomic context | ||
952 | */ | ||
953 | int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), | ||
954 | struct list_head *head, void *data) | ||
955 | { | ||
956 | int err = 0; | ||
957 | |||
958 | efivar_entry_iter_begin(); | ||
959 | err = __efivar_entry_iter(func, head, data, NULL); | ||
960 | efivar_entry_iter_end(); | ||
961 | |||
962 | return err; | ||
963 | } | ||
964 | EXPORT_SYMBOL_GPL(efivar_entry_iter); | ||
965 | |||
966 | /** | ||
967 | * efivars_kobject - get the kobject for the registered efivars | ||
968 | * | ||
969 | * If efivars_register() has not been called we return NULL, | ||
970 | * otherwise return the kobject used at registration time. | ||
971 | */ | ||
972 | struct kobject *efivars_kobject(void) | ||
973 | { | ||
974 | if (!__efivars) | ||
975 | return NULL; | ||
976 | |||
977 | return __efivars->kobject; | ||
978 | } | ||
979 | EXPORT_SYMBOL_GPL(efivars_kobject); | ||
980 | |||
981 | /** | ||
982 | * efivar_run_worker - schedule the efivar worker thread | ||
983 | */ | ||
984 | void efivar_run_worker(void) | ||
985 | { | ||
986 | if (efivar_wq_enabled) | ||
987 | schedule_work(&efivar_work); | ||
988 | } | ||
989 | EXPORT_SYMBOL_GPL(efivar_run_worker); | ||
990 | |||
991 | /** | ||
992 | * efivars_register - register an efivars | ||
993 | * @efivars: efivars to register | ||
994 | * @ops: efivars operations | ||
995 | * @kobject: @efivars-specific kobject | ||
996 | * | ||
997 | * Only a single efivars can be registered at any time. | ||
998 | */ | ||
999 | int efivars_register(struct efivars *efivars, | ||
1000 | const struct efivar_operations *ops, | ||
1001 | struct kobject *kobject) | ||
1002 | { | ||
1003 | spin_lock_init(&efivars->lock); | ||
1004 | efivars->ops = ops; | ||
1005 | efivars->kobject = kobject; | ||
1006 | |||
1007 | __efivars = efivars; | ||
1008 | |||
1009 | return 0; | ||
1010 | } | ||
1011 | EXPORT_SYMBOL_GPL(efivars_register); | ||
1012 | |||
1013 | /** | ||
1014 | * efivars_unregister - unregister an efivars | ||
1015 | * @efivars: efivars to unregister | ||
1016 | * | ||
1017 | * The caller must have already removed every entry from the list, | ||
1018 | * failure to do so is an error. | ||
1019 | */ | ||
1020 | int efivars_unregister(struct efivars *efivars) | ||
1021 | { | ||
1022 | int rv; | ||
1023 | |||
1024 | if (!__efivars) { | ||
1025 | printk(KERN_ERR "efivars not registered\n"); | ||
1026 | rv = -EINVAL; | ||
1027 | goto out; | ||
1028 | } | ||
1029 | |||
1030 | if (__efivars != efivars) { | ||
1031 | rv = -EINVAL; | ||
1032 | goto out; | ||
1033 | } | ||
1034 | |||
1035 | __efivars = NULL; | ||
1036 | |||
1037 | rv = 0; | ||
1038 | out: | ||
1039 | return rv; | ||
1040 | } | ||
1041 | EXPORT_SYMBOL_GPL(efivars_unregister); | ||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c deleted file mode 100644 index f4baa11d3644..000000000000 --- a/drivers/firmware/efivars.c +++ /dev/null | |||
@@ -1,2117 +0,0 @@ | |||
1 | /* | ||
2 | * EFI Variables - efivars.c | ||
3 | * | ||
4 | * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> | ||
5 | * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> | ||
6 | * | ||
7 | * This code takes all variables accessible from EFI runtime and | ||
8 | * exports them via sysfs | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Changelog: | ||
25 | * | ||
26 | * 17 May 2004 - Matt Domsch <Matt_Domsch@dell.com> | ||
27 | * remove check for efi_enabled in exit | ||
28 | * add MODULE_VERSION | ||
29 | * | ||
30 | * 26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com> | ||
31 | * minor bug fixes | ||
32 | * | ||
33 | * 21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com) | ||
34 | * converted driver to export variable information via sysfs | ||
35 | * and moved to drivers/firmware directory | ||
36 | * bumped revision number to v0.07 to reflect conversion & move | ||
37 | * | ||
38 | * 10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com> | ||
39 | * fix locking per Peter Chubb's findings | ||
40 | * | ||
41 | * 25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com> | ||
42 | * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse() | ||
43 | * | ||
44 | * 12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com> | ||
45 | * use list_for_each_safe when deleting vars. | ||
46 | * remove ifdef CONFIG_SMP around include <linux/smp.h> | ||
47 | * v0.04 release to linux-ia64@linuxia64.org | ||
48 | * | ||
49 | * 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
50 | * Moved vars from /proc/efi to /proc/efi/vars, and made | ||
51 | * efi.c own the /proc/efi directory. | ||
52 | * v0.03 release to linux-ia64@linuxia64.org | ||
53 | * | ||
54 | * 26 March 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
55 | * At the request of Stephane, moved ownership of /proc/efi | ||
56 | * to efi.c, and now efivars lives under /proc/efi/vars. | ||
57 | * | ||
58 | * 12 March 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
59 | * Feedback received from Stephane Eranian incorporated. | ||
60 | * efivar_write() checks copy_from_user() return value. | ||
61 | * efivar_read/write() returns proper errno. | ||
62 | * v0.02 release to linux-ia64@linuxia64.org | ||
63 | * | ||
64 | * 26 February 2001 - Matt Domsch <Matt_Domsch@dell.com> | ||
65 | * v0.01 release to linux-ia64@linuxia64.org | ||
66 | */ | ||
67 | |||
68 | #include <linux/capability.h> | ||
69 | #include <linux/types.h> | ||
70 | #include <linux/errno.h> | ||
71 | #include <linux/init.h> | ||
72 | #include <linux/mm.h> | ||
73 | #include <linux/module.h> | ||
74 | #include <linux/string.h> | ||
75 | #include <linux/smp.h> | ||
76 | #include <linux/efi.h> | ||
77 | #include <linux/sysfs.h> | ||
78 | #include <linux/kobject.h> | ||
79 | #include <linux/device.h> | ||
80 | #include <linux/slab.h> | ||
81 | #include <linux/pstore.h> | ||
82 | #include <linux/ctype.h> | ||
83 | #include <linux/ucs2_string.h> | ||
84 | |||
85 | #include <linux/fs.h> | ||
86 | #include <linux/ramfs.h> | ||
87 | #include <linux/pagemap.h> | ||
88 | |||
89 | #include <asm/uaccess.h> | ||
90 | |||
91 | #define EFIVARS_VERSION "0.08" | ||
92 | #define EFIVARS_DATE "2004-May-17" | ||
93 | |||
94 | MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); | ||
95 | MODULE_DESCRIPTION("sysfs interface to EFI Variables"); | ||
96 | MODULE_LICENSE("GPL"); | ||
97 | MODULE_VERSION(EFIVARS_VERSION); | ||
98 | |||
99 | #define DUMP_NAME_LEN 52 | ||
100 | |||
101 | /* | ||
102 | * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")) | ||
103 | * not including trailing NUL | ||
104 | */ | ||
105 | #define GUID_LEN 36 | ||
106 | |||
107 | static bool efivars_pstore_disable = | ||
108 | IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE); | ||
109 | |||
110 | module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644); | ||
111 | |||
112 | /* | ||
113 | * The maximum size of VariableName + Data = 1024 | ||
114 | * Therefore, it's reasonable to save that much | ||
115 | * space in each part of the structure, | ||
116 | * and we use a page for reading/writing. | ||
117 | */ | ||
118 | |||
119 | struct efi_variable { | ||
120 | efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; | ||
121 | efi_guid_t VendorGuid; | ||
122 | unsigned long DataSize; | ||
123 | __u8 Data[1024]; | ||
124 | efi_status_t Status; | ||
125 | __u32 Attributes; | ||
126 | } __attribute__((packed)); | ||
127 | |||
128 | struct efivar_entry { | ||
129 | struct efivars *efivars; | ||
130 | struct efi_variable var; | ||
131 | struct list_head list; | ||
132 | struct kobject kobj; | ||
133 | }; | ||
134 | |||
135 | struct efivar_attribute { | ||
136 | struct attribute attr; | ||
137 | ssize_t (*show) (struct efivar_entry *entry, char *buf); | ||
138 | ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); | ||
139 | }; | ||
140 | |||
141 | static struct efivars __efivars; | ||
142 | static struct efivar_operations ops; | ||
143 | |||
144 | #define PSTORE_EFI_ATTRIBUTES \ | ||
145 | (EFI_VARIABLE_NON_VOLATILE | \ | ||
146 | EFI_VARIABLE_BOOTSERVICE_ACCESS | \ | ||
147 | EFI_VARIABLE_RUNTIME_ACCESS) | ||
148 | |||
149 | #define EFIVAR_ATTR(_name, _mode, _show, _store) \ | ||
150 | struct efivar_attribute efivar_attr_##_name = { \ | ||
151 | .attr = {.name = __stringify(_name), .mode = _mode}, \ | ||
152 | .show = _show, \ | ||
153 | .store = _store, \ | ||
154 | }; | ||
155 | |||
156 | #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr) | ||
157 | #define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj) | ||
158 | |||
159 | /* | ||
160 | * Prototype for sysfs creation function | ||
161 | */ | ||
162 | static int | ||
163 | efivar_create_sysfs_entry(struct efivars *efivars, | ||
164 | unsigned long variable_name_size, | ||
165 | efi_char16_t *variable_name, | ||
166 | efi_guid_t *vendor_guid); | ||
167 | |||
168 | /* | ||
169 | * Prototype for workqueue functions updating sysfs entry | ||
170 | */ | ||
171 | |||
172 | static void efivar_update_sysfs_entries(struct work_struct *); | ||
173 | static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); | ||
174 | static bool efivar_wq_enabled = true; | ||
175 | |||
176 | static bool | ||
177 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, | ||
178 | unsigned long len) | ||
179 | { | ||
180 | struct efi_generic_dev_path *node; | ||
181 | int offset = 0; | ||
182 | |||
183 | node = (struct efi_generic_dev_path *)buffer; | ||
184 | |||
185 | if (len < sizeof(*node)) | ||
186 | return false; | ||
187 | |||
188 | while (offset <= len - sizeof(*node) && | ||
189 | node->length >= sizeof(*node) && | ||
190 | node->length <= len - offset) { | ||
191 | offset += node->length; | ||
192 | |||
193 | if ((node->type == EFI_DEV_END_PATH || | ||
194 | node->type == EFI_DEV_END_PATH2) && | ||
195 | node->sub_type == EFI_DEV_END_ENTIRE) | ||
196 | return true; | ||
197 | |||
198 | node = (struct efi_generic_dev_path *)(buffer + offset); | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * If we're here then either node->length pointed past the end | ||
203 | * of the buffer or we reached the end of the buffer without | ||
204 | * finding a device path end node. | ||
205 | */ | ||
206 | return false; | ||
207 | } | ||
208 | |||
209 | static bool | ||
210 | validate_boot_order(struct efi_variable *var, int match, u8 *buffer, | ||
211 | unsigned long len) | ||
212 | { | ||
213 | /* An array of 16-bit integers */ | ||
214 | if ((len % 2) != 0) | ||
215 | return false; | ||
216 | |||
217 | return true; | ||
218 | } | ||
219 | |||
220 | static bool | ||
221 | validate_load_option(struct efi_variable *var, int match, u8 *buffer, | ||
222 | unsigned long len) | ||
223 | { | ||
224 | u16 filepathlength; | ||
225 | int i, desclength = 0, namelen; | ||
226 | |||
227 | namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); | ||
228 | |||
229 | /* Either "Boot" or "Driver" followed by four digits of hex */ | ||
230 | for (i = match; i < match+4; i++) { | ||
231 | if (var->VariableName[i] > 127 || | ||
232 | hex_to_bin(var->VariableName[i] & 0xff) < 0) | ||
233 | return true; | ||
234 | } | ||
235 | |||
236 | /* Reject it if there's 4 digits of hex and then further content */ | ||
237 | if (namelen > match + 4) | ||
238 | return false; | ||
239 | |||
240 | /* A valid entry must be at least 8 bytes */ | ||
241 | if (len < 8) | ||
242 | return false; | ||
243 | |||
244 | filepathlength = buffer[4] | buffer[5] << 8; | ||
245 | |||
246 | /* | ||
247 | * There's no stored length for the description, so it has to be | ||
248 | * found by hand | ||
249 | */ | ||
250 | desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; | ||
251 | |||
252 | /* Each boot entry must have a descriptor */ | ||
253 | if (!desclength) | ||
254 | return false; | ||
255 | |||
256 | /* | ||
257 | * If the sum of the length of the description, the claimed filepath | ||
258 | * length and the original header are greater than the length of the | ||
259 | * variable, it's malformed | ||
260 | */ | ||
261 | if ((desclength + filepathlength + 6) > len) | ||
262 | return false; | ||
263 | |||
264 | /* | ||
265 | * And, finally, check the filepath | ||
266 | */ | ||
267 | return validate_device_path(var, match, buffer + desclength + 6, | ||
268 | filepathlength); | ||
269 | } | ||
270 | |||
271 | static bool | ||
272 | validate_uint16(struct efi_variable *var, int match, u8 *buffer, | ||
273 | unsigned long len) | ||
274 | { | ||
275 | /* A single 16-bit integer */ | ||
276 | if (len != 2) | ||
277 | return false; | ||
278 | |||
279 | return true; | ||
280 | } | ||
281 | |||
282 | static bool | ||
283 | validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, | ||
284 | unsigned long len) | ||
285 | { | ||
286 | int i; | ||
287 | |||
288 | for (i = 0; i < len; i++) { | ||
289 | if (buffer[i] > 127) | ||
290 | return false; | ||
291 | |||
292 | if (buffer[i] == 0) | ||
293 | return true; | ||
294 | } | ||
295 | |||
296 | return false; | ||
297 | } | ||
298 | |||
299 | struct variable_validate { | ||
300 | char *name; | ||
301 | bool (*validate)(struct efi_variable *var, int match, u8 *data, | ||
302 | unsigned long len); | ||
303 | }; | ||
304 | |||
305 | static const struct variable_validate variable_validate[] = { | ||
306 | { "BootNext", validate_uint16 }, | ||
307 | { "BootOrder", validate_boot_order }, | ||
308 | { "DriverOrder", validate_boot_order }, | ||
309 | { "Boot*", validate_load_option }, | ||
310 | { "Driver*", validate_load_option }, | ||
311 | { "ConIn", validate_device_path }, | ||
312 | { "ConInDev", validate_device_path }, | ||
313 | { "ConOut", validate_device_path }, | ||
314 | { "ConOutDev", validate_device_path }, | ||
315 | { "ErrOut", validate_device_path }, | ||
316 | { "ErrOutDev", validate_device_path }, | ||
317 | { "Timeout", validate_uint16 }, | ||
318 | { "Lang", validate_ascii_string }, | ||
319 | { "PlatformLang", validate_ascii_string }, | ||
320 | { "", NULL }, | ||
321 | }; | ||
322 | |||
323 | static bool | ||
324 | validate_var(struct efi_variable *var, u8 *data, unsigned long len) | ||
325 | { | ||
326 | int i; | ||
327 | u16 *unicode_name = var->VariableName; | ||
328 | |||
329 | for (i = 0; variable_validate[i].validate != NULL; i++) { | ||
330 | const char *name = variable_validate[i].name; | ||
331 | int match; | ||
332 | |||
333 | for (match = 0; ; match++) { | ||
334 | char c = name[match]; | ||
335 | u16 u = unicode_name[match]; | ||
336 | |||
337 | /* All special variables are plain ascii */ | ||
338 | if (u > 127) | ||
339 | return true; | ||
340 | |||
341 | /* Wildcard in the matching name means we've matched */ | ||
342 | if (c == '*') | ||
343 | return variable_validate[i].validate(var, | ||
344 | match, data, len); | ||
345 | |||
346 | /* Case sensitive match */ | ||
347 | if (c != u) | ||
348 | break; | ||
349 | |||
350 | /* Reached the end of the string while matching */ | ||
351 | if (!c) | ||
352 | return variable_validate[i].validate(var, | ||
353 | match, data, len); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | return true; | ||
358 | } | ||
359 | |||
360 | static efi_status_t | ||
361 | get_var_data_locked(struct efivars *efivars, struct efi_variable *var) | ||
362 | { | ||
363 | efi_status_t status; | ||
364 | |||
365 | var->DataSize = 1024; | ||
366 | status = efivars->ops->get_variable(var->VariableName, | ||
367 | &var->VendorGuid, | ||
368 | &var->Attributes, | ||
369 | &var->DataSize, | ||
370 | var->Data); | ||
371 | return status; | ||
372 | } | ||
373 | |||
374 | static efi_status_t | ||
375 | get_var_data(struct efivars *efivars, struct efi_variable *var) | ||
376 | { | ||
377 | efi_status_t status; | ||
378 | unsigned long flags; | ||
379 | |||
380 | spin_lock_irqsave(&efivars->lock, flags); | ||
381 | status = get_var_data_locked(efivars, var); | ||
382 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
383 | |||
384 | if (status != EFI_SUCCESS) { | ||
385 | printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n", | ||
386 | status); | ||
387 | } | ||
388 | return status; | ||
389 | } | ||
390 | |||
391 | static efi_status_t | ||
392 | check_var_size_locked(struct efivars *efivars, u32 attributes, | ||
393 | unsigned long size) | ||
394 | { | ||
395 | const struct efivar_operations *fops = efivars->ops; | ||
396 | |||
397 | if (!efivars->ops->query_variable_store) | ||
398 | return EFI_UNSUPPORTED; | ||
399 | |||
400 | return fops->query_variable_store(attributes, size); | ||
401 | } | ||
402 | |||
403 | |||
404 | static efi_status_t | ||
405 | check_var_size(struct efivars *efivars, u32 attributes, unsigned long size) | ||
406 | { | ||
407 | efi_status_t status; | ||
408 | unsigned long flags; | ||
409 | |||
410 | spin_lock_irqsave(&efivars->lock, flags); | ||
411 | status = check_var_size_locked(efivars, attributes, size); | ||
412 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
413 | |||
414 | return status; | ||
415 | } | ||
416 | |||
417 | static ssize_t | ||
418 | efivar_guid_read(struct efivar_entry *entry, char *buf) | ||
419 | { | ||
420 | struct efi_variable *var = &entry->var; | ||
421 | char *str = buf; | ||
422 | |||
423 | if (!entry || !buf) | ||
424 | return 0; | ||
425 | |||
426 | efi_guid_unparse(&var->VendorGuid, str); | ||
427 | str += strlen(str); | ||
428 | str += sprintf(str, "\n"); | ||
429 | |||
430 | return str - buf; | ||
431 | } | ||
432 | |||
433 | static ssize_t | ||
434 | efivar_attr_read(struct efivar_entry *entry, char *buf) | ||
435 | { | ||
436 | struct efi_variable *var = &entry->var; | ||
437 | char *str = buf; | ||
438 | efi_status_t status; | ||
439 | |||
440 | if (!entry || !buf) | ||
441 | return -EINVAL; | ||
442 | |||
443 | status = get_var_data(entry->efivars, var); | ||
444 | if (status != EFI_SUCCESS) | ||
445 | return -EIO; | ||
446 | |||
447 | if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) | ||
448 | str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n"); | ||
449 | if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) | ||
450 | str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n"); | ||
451 | if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) | ||
452 | str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n"); | ||
453 | if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) | ||
454 | str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n"); | ||
455 | if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) | ||
456 | str += sprintf(str, | ||
457 | "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n"); | ||
458 | if (var->Attributes & | ||
459 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) | ||
460 | str += sprintf(str, | ||
461 | "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n"); | ||
462 | if (var->Attributes & EFI_VARIABLE_APPEND_WRITE) | ||
463 | str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n"); | ||
464 | return str - buf; | ||
465 | } | ||
466 | |||
467 | static ssize_t | ||
468 | efivar_size_read(struct efivar_entry *entry, char *buf) | ||
469 | { | ||
470 | struct efi_variable *var = &entry->var; | ||
471 | char *str = buf; | ||
472 | efi_status_t status; | ||
473 | |||
474 | if (!entry || !buf) | ||
475 | return -EINVAL; | ||
476 | |||
477 | status = get_var_data(entry->efivars, var); | ||
478 | if (status != EFI_SUCCESS) | ||
479 | return -EIO; | ||
480 | |||
481 | str += sprintf(str, "0x%lx\n", var->DataSize); | ||
482 | return str - buf; | ||
483 | } | ||
484 | |||
485 | static ssize_t | ||
486 | efivar_data_read(struct efivar_entry *entry, char *buf) | ||
487 | { | ||
488 | struct efi_variable *var = &entry->var; | ||
489 | efi_status_t status; | ||
490 | |||
491 | if (!entry || !buf) | ||
492 | return -EINVAL; | ||
493 | |||
494 | status = get_var_data(entry->efivars, var); | ||
495 | if (status != EFI_SUCCESS) | ||
496 | return -EIO; | ||
497 | |||
498 | memcpy(buf, var->Data, var->DataSize); | ||
499 | return var->DataSize; | ||
500 | } | ||
501 | /* | ||
502 | * We allow each variable to be edited via rewriting the | ||
503 | * entire efi variable structure. | ||
504 | */ | ||
505 | static ssize_t | ||
506 | efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | ||
507 | { | ||
508 | struct efi_variable *new_var, *var = &entry->var; | ||
509 | struct efivars *efivars = entry->efivars; | ||
510 | efi_status_t status = EFI_NOT_FOUND; | ||
511 | |||
512 | if (count != sizeof(struct efi_variable)) | ||
513 | return -EINVAL; | ||
514 | |||
515 | new_var = (struct efi_variable *)buf; | ||
516 | /* | ||
517 | * If only updating the variable data, then the name | ||
518 | * and guid should remain the same | ||
519 | */ | ||
520 | if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || | ||
521 | efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { | ||
522 | printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); | ||
523 | return -EINVAL; | ||
524 | } | ||
525 | |||
526 | if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ | ||
527 | printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | |||
531 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
532 | validate_var(new_var, new_var->Data, new_var->DataSize) == false) { | ||
533 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | spin_lock_irq(&efivars->lock); | ||
538 | |||
539 | status = check_var_size_locked(efivars, new_var->Attributes, | ||
540 | new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024)); | ||
541 | |||
542 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) | ||
543 | status = efivars->ops->set_variable(new_var->VariableName, | ||
544 | &new_var->VendorGuid, | ||
545 | new_var->Attributes, | ||
546 | new_var->DataSize, | ||
547 | new_var->Data); | ||
548 | |||
549 | spin_unlock_irq(&efivars->lock); | ||
550 | |||
551 | if (status != EFI_SUCCESS) { | ||
552 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | ||
553 | status); | ||
554 | return -EIO; | ||
555 | } | ||
556 | |||
557 | memcpy(&entry->var, new_var, count); | ||
558 | return count; | ||
559 | } | ||
560 | |||
561 | static ssize_t | ||
562 | efivar_show_raw(struct efivar_entry *entry, char *buf) | ||
563 | { | ||
564 | struct efi_variable *var = &entry->var; | ||
565 | efi_status_t status; | ||
566 | |||
567 | if (!entry || !buf) | ||
568 | return 0; | ||
569 | |||
570 | status = get_var_data(entry->efivars, var); | ||
571 | if (status != EFI_SUCCESS) | ||
572 | return -EIO; | ||
573 | |||
574 | memcpy(buf, var, sizeof(*var)); | ||
575 | return sizeof(*var); | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * Generic read/write functions that call the specific functions of | ||
580 | * the attributes... | ||
581 | */ | ||
582 | static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr, | ||
583 | char *buf) | ||
584 | { | ||
585 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
586 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
587 | ssize_t ret = -EIO; | ||
588 | |||
589 | if (!capable(CAP_SYS_ADMIN)) | ||
590 | return -EACCES; | ||
591 | |||
592 | if (efivar_attr->show) { | ||
593 | ret = efivar_attr->show(var, buf); | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, | ||
599 | const char *buf, size_t count) | ||
600 | { | ||
601 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
602 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
603 | ssize_t ret = -EIO; | ||
604 | |||
605 | if (!capable(CAP_SYS_ADMIN)) | ||
606 | return -EACCES; | ||
607 | |||
608 | if (efivar_attr->store) | ||
609 | ret = efivar_attr->store(var, buf, count); | ||
610 | |||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | static const struct sysfs_ops efivar_attr_ops = { | ||
615 | .show = efivar_attr_show, | ||
616 | .store = efivar_attr_store, | ||
617 | }; | ||
618 | |||
619 | static void efivar_release(struct kobject *kobj) | ||
620 | { | ||
621 | struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj); | ||
622 | kfree(var); | ||
623 | } | ||
624 | |||
625 | static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL); | ||
626 | static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL); | ||
627 | static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL); | ||
628 | static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL); | ||
629 | static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw); | ||
630 | |||
631 | static struct attribute *def_attrs[] = { | ||
632 | &efivar_attr_guid.attr, | ||
633 | &efivar_attr_size.attr, | ||
634 | &efivar_attr_attributes.attr, | ||
635 | &efivar_attr_data.attr, | ||
636 | &efivar_attr_raw_var.attr, | ||
637 | NULL, | ||
638 | }; | ||
639 | |||
640 | static struct kobj_type efivar_ktype = { | ||
641 | .release = efivar_release, | ||
642 | .sysfs_ops = &efivar_attr_ops, | ||
643 | .default_attrs = def_attrs, | ||
644 | }; | ||
645 | |||
646 | static inline void | ||
647 | efivar_unregister(struct efivar_entry *var) | ||
648 | { | ||
649 | kobject_put(&var->kobj); | ||
650 | } | ||
651 | |||
652 | static int efivarfs_file_open(struct inode *inode, struct file *file) | ||
653 | { | ||
654 | file->private_data = inode->i_private; | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int efi_status_to_err(efi_status_t status) | ||
659 | { | ||
660 | int err; | ||
661 | |||
662 | switch (status) { | ||
663 | case EFI_INVALID_PARAMETER: | ||
664 | err = -EINVAL; | ||
665 | break; | ||
666 | case EFI_OUT_OF_RESOURCES: | ||
667 | err = -ENOSPC; | ||
668 | break; | ||
669 | case EFI_DEVICE_ERROR: | ||
670 | err = -EIO; | ||
671 | break; | ||
672 | case EFI_WRITE_PROTECTED: | ||
673 | err = -EROFS; | ||
674 | break; | ||
675 | case EFI_SECURITY_VIOLATION: | ||
676 | err = -EACCES; | ||
677 | break; | ||
678 | case EFI_NOT_FOUND: | ||
679 | err = -EIO; | ||
680 | break; | ||
681 | default: | ||
682 | err = -EINVAL; | ||
683 | } | ||
684 | |||
685 | return err; | ||
686 | } | ||
687 | |||
688 | static ssize_t efivarfs_file_write(struct file *file, | ||
689 | const char __user *userbuf, size_t count, loff_t *ppos) | ||
690 | { | ||
691 | struct efivar_entry *var = file->private_data; | ||
692 | struct efivars *efivars; | ||
693 | efi_status_t status; | ||
694 | void *data; | ||
695 | u32 attributes; | ||
696 | struct inode *inode = file->f_mapping->host; | ||
697 | unsigned long datasize = count - sizeof(attributes); | ||
698 | unsigned long newdatasize, varsize; | ||
699 | ssize_t bytes = 0; | ||
700 | |||
701 | if (count < sizeof(attributes)) | ||
702 | return -EINVAL; | ||
703 | |||
704 | if (copy_from_user(&attributes, userbuf, sizeof(attributes))) | ||
705 | return -EFAULT; | ||
706 | |||
707 | if (attributes & ~(EFI_VARIABLE_MASK)) | ||
708 | return -EINVAL; | ||
709 | |||
710 | efivars = var->efivars; | ||
711 | |||
712 | /* | ||
713 | * Ensure that the user can't allocate arbitrarily large | ||
714 | * amounts of memory. Pick a default size of 64K if | ||
715 | * QueryVariableInfo() isn't supported by the firmware. | ||
716 | */ | ||
717 | |||
718 | varsize = datasize + ucs2_strsize(var->var.VariableName, 1024); | ||
719 | status = check_var_size(efivars, attributes, varsize); | ||
720 | |||
721 | if (status != EFI_SUCCESS) { | ||
722 | if (status != EFI_UNSUPPORTED) | ||
723 | return efi_status_to_err(status); | ||
724 | |||
725 | if (datasize > 65536) | ||
726 | return -ENOSPC; | ||
727 | } | ||
728 | |||
729 | data = kmalloc(datasize, GFP_KERNEL); | ||
730 | if (!data) | ||
731 | return -ENOMEM; | ||
732 | |||
733 | if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) { | ||
734 | bytes = -EFAULT; | ||
735 | goto out; | ||
736 | } | ||
737 | |||
738 | if (validate_var(&var->var, data, datasize) == false) { | ||
739 | bytes = -EINVAL; | ||
740 | goto out; | ||
741 | } | ||
742 | |||
743 | /* | ||
744 | * The lock here protects the get_variable call, the conditional | ||
745 | * set_variable call, and removal of the variable from the efivars | ||
746 | * list (in the case of an authenticated delete). | ||
747 | */ | ||
748 | spin_lock_irq(&efivars->lock); | ||
749 | |||
750 | /* | ||
751 | * Ensure that the available space hasn't shrunk below the safe level | ||
752 | */ | ||
753 | |||
754 | status = check_var_size_locked(efivars, attributes, varsize); | ||
755 | |||
756 | if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) { | ||
757 | spin_unlock_irq(&efivars->lock); | ||
758 | kfree(data); | ||
759 | |||
760 | return efi_status_to_err(status); | ||
761 | } | ||
762 | |||
763 | status = efivars->ops->set_variable(var->var.VariableName, | ||
764 | &var->var.VendorGuid, | ||
765 | attributes, datasize, | ||
766 | data); | ||
767 | |||
768 | if (status != EFI_SUCCESS) { | ||
769 | spin_unlock_irq(&efivars->lock); | ||
770 | kfree(data); | ||
771 | |||
772 | return efi_status_to_err(status); | ||
773 | } | ||
774 | |||
775 | bytes = count; | ||
776 | |||
777 | /* | ||
778 | * Writing to the variable may have caused a change in size (which | ||
779 | * could either be an append or an overwrite), or the variable to be | ||
780 | * deleted. Perform a GetVariable() so we can tell what actually | ||
781 | * happened. | ||
782 | */ | ||
783 | newdatasize = 0; | ||
784 | status = efivars->ops->get_variable(var->var.VariableName, | ||
785 | &var->var.VendorGuid, | ||
786 | NULL, &newdatasize, | ||
787 | NULL); | ||
788 | |||
789 | if (status == EFI_BUFFER_TOO_SMALL) { | ||
790 | spin_unlock_irq(&efivars->lock); | ||
791 | mutex_lock(&inode->i_mutex); | ||
792 | i_size_write(inode, newdatasize + sizeof(attributes)); | ||
793 | mutex_unlock(&inode->i_mutex); | ||
794 | |||
795 | } else if (status == EFI_NOT_FOUND) { | ||
796 | list_del(&var->list); | ||
797 | spin_unlock_irq(&efivars->lock); | ||
798 | efivar_unregister(var); | ||
799 | drop_nlink(inode); | ||
800 | d_delete(file->f_dentry); | ||
801 | dput(file->f_dentry); | ||
802 | |||
803 | } else { | ||
804 | spin_unlock_irq(&efivars->lock); | ||
805 | pr_warn("efivarfs: inconsistent EFI variable implementation? " | ||
806 | "status = %lx\n", status); | ||
807 | } | ||
808 | |||
809 | out: | ||
810 | kfree(data); | ||
811 | |||
812 | return bytes; | ||
813 | } | ||
814 | |||
815 | static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, | ||
816 | size_t count, loff_t *ppos) | ||
817 | { | ||
818 | struct efivar_entry *var = file->private_data; | ||
819 | struct efivars *efivars = var->efivars; | ||
820 | efi_status_t status; | ||
821 | unsigned long datasize = 0; | ||
822 | u32 attributes; | ||
823 | void *data; | ||
824 | ssize_t size = 0; | ||
825 | |||
826 | spin_lock_irq(&efivars->lock); | ||
827 | status = efivars->ops->get_variable(var->var.VariableName, | ||
828 | &var->var.VendorGuid, | ||
829 | &attributes, &datasize, NULL); | ||
830 | spin_unlock_irq(&efivars->lock); | ||
831 | |||
832 | if (status != EFI_BUFFER_TOO_SMALL) | ||
833 | return efi_status_to_err(status); | ||
834 | |||
835 | data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); | ||
836 | |||
837 | if (!data) | ||
838 | return -ENOMEM; | ||
839 | |||
840 | spin_lock_irq(&efivars->lock); | ||
841 | status = efivars->ops->get_variable(var->var.VariableName, | ||
842 | &var->var.VendorGuid, | ||
843 | &attributes, &datasize, | ||
844 | (data + sizeof(attributes))); | ||
845 | spin_unlock_irq(&efivars->lock); | ||
846 | |||
847 | if (status != EFI_SUCCESS) { | ||
848 | size = efi_status_to_err(status); | ||
849 | goto out_free; | ||
850 | } | ||
851 | |||
852 | memcpy(data, &attributes, sizeof(attributes)); | ||
853 | size = simple_read_from_buffer(userbuf, count, ppos, | ||
854 | data, datasize + sizeof(attributes)); | ||
855 | out_free: | ||
856 | kfree(data); | ||
857 | |||
858 | return size; | ||
859 | } | ||
860 | |||
861 | static void efivarfs_evict_inode(struct inode *inode) | ||
862 | { | ||
863 | clear_inode(inode); | ||
864 | } | ||
865 | |||
866 | static const struct super_operations efivarfs_ops = { | ||
867 | .statfs = simple_statfs, | ||
868 | .drop_inode = generic_delete_inode, | ||
869 | .evict_inode = efivarfs_evict_inode, | ||
870 | .show_options = generic_show_options, | ||
871 | }; | ||
872 | |||
873 | static struct super_block *efivarfs_sb; | ||
874 | |||
875 | static const struct inode_operations efivarfs_dir_inode_operations; | ||
876 | |||
877 | static const struct file_operations efivarfs_file_operations = { | ||
878 | .open = efivarfs_file_open, | ||
879 | .read = efivarfs_file_read, | ||
880 | .write = efivarfs_file_write, | ||
881 | .llseek = no_llseek, | ||
882 | }; | ||
883 | |||
884 | static struct inode *efivarfs_get_inode(struct super_block *sb, | ||
885 | const struct inode *dir, int mode, dev_t dev) | ||
886 | { | ||
887 | struct inode *inode = new_inode(sb); | ||
888 | |||
889 | if (inode) { | ||
890 | inode->i_ino = get_next_ino(); | ||
891 | inode->i_mode = mode; | ||
892 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
893 | switch (mode & S_IFMT) { | ||
894 | case S_IFREG: | ||
895 | inode->i_fop = &efivarfs_file_operations; | ||
896 | break; | ||
897 | case S_IFDIR: | ||
898 | inode->i_op = &efivarfs_dir_inode_operations; | ||
899 | inode->i_fop = &simple_dir_operations; | ||
900 | inc_nlink(inode); | ||
901 | break; | ||
902 | } | ||
903 | } | ||
904 | return inode; | ||
905 | } | ||
906 | |||
907 | /* | ||
908 | * Return true if 'str' is a valid efivarfs filename of the form, | ||
909 | * | ||
910 | * VariableName-12345678-1234-1234-1234-1234567891bc | ||
911 | */ | ||
912 | static bool efivarfs_valid_name(const char *str, int len) | ||
913 | { | ||
914 | static const char dashes[GUID_LEN] = { | ||
915 | [8] = 1, [13] = 1, [18] = 1, [23] = 1 | ||
916 | }; | ||
917 | const char *s = str + len - GUID_LEN; | ||
918 | int i; | ||
919 | |||
920 | /* | ||
921 | * We need a GUID, plus at least one letter for the variable name, | ||
922 | * plus the '-' separator | ||
923 | */ | ||
924 | if (len < GUID_LEN + 2) | ||
925 | return false; | ||
926 | |||
927 | /* GUID must be preceded by a '-' */ | ||
928 | if (*(s - 1) != '-') | ||
929 | return false; | ||
930 | |||
931 | /* | ||
932 | * Validate that 's' is of the correct format, e.g. | ||
933 | * | ||
934 | * 12345678-1234-1234-1234-123456789abc | ||
935 | */ | ||
936 | for (i = 0; i < GUID_LEN; i++) { | ||
937 | if (dashes[i]) { | ||
938 | if (*s++ != '-') | ||
939 | return false; | ||
940 | } else { | ||
941 | if (!isxdigit(*s++)) | ||
942 | return false; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | return true; | ||
947 | } | ||
948 | |||
949 | static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) | ||
950 | { | ||
951 | guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]); | ||
952 | guid->b[1] = hex_to_bin(str[4]) << 4 | hex_to_bin(str[5]); | ||
953 | guid->b[2] = hex_to_bin(str[2]) << 4 | hex_to_bin(str[3]); | ||
954 | guid->b[3] = hex_to_bin(str[0]) << 4 | hex_to_bin(str[1]); | ||
955 | guid->b[4] = hex_to_bin(str[11]) << 4 | hex_to_bin(str[12]); | ||
956 | guid->b[5] = hex_to_bin(str[9]) << 4 | hex_to_bin(str[10]); | ||
957 | guid->b[6] = hex_to_bin(str[16]) << 4 | hex_to_bin(str[17]); | ||
958 | guid->b[7] = hex_to_bin(str[14]) << 4 | hex_to_bin(str[15]); | ||
959 | guid->b[8] = hex_to_bin(str[19]) << 4 | hex_to_bin(str[20]); | ||
960 | guid->b[9] = hex_to_bin(str[21]) << 4 | hex_to_bin(str[22]); | ||
961 | guid->b[10] = hex_to_bin(str[24]) << 4 | hex_to_bin(str[25]); | ||
962 | guid->b[11] = hex_to_bin(str[26]) << 4 | hex_to_bin(str[27]); | ||
963 | guid->b[12] = hex_to_bin(str[28]) << 4 | hex_to_bin(str[29]); | ||
964 | guid->b[13] = hex_to_bin(str[30]) << 4 | hex_to_bin(str[31]); | ||
965 | guid->b[14] = hex_to_bin(str[32]) << 4 | hex_to_bin(str[33]); | ||
966 | guid->b[15] = hex_to_bin(str[34]) << 4 | hex_to_bin(str[35]); | ||
967 | } | ||
968 | |||
969 | static int efivarfs_create(struct inode *dir, struct dentry *dentry, | ||
970 | umode_t mode, bool excl) | ||
971 | { | ||
972 | struct inode *inode; | ||
973 | struct efivars *efivars = &__efivars; | ||
974 | struct efivar_entry *var; | ||
975 | int namelen, i = 0, err = 0; | ||
976 | |||
977 | if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) | ||
978 | return -EINVAL; | ||
979 | |||
980 | inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); | ||
981 | if (!inode) | ||
982 | return -ENOMEM; | ||
983 | |||
984 | var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); | ||
985 | if (!var) { | ||
986 | err = -ENOMEM; | ||
987 | goto out; | ||
988 | } | ||
989 | |||
990 | /* length of the variable name itself: remove GUID and separator */ | ||
991 | namelen = dentry->d_name.len - GUID_LEN - 1; | ||
992 | |||
993 | efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, | ||
994 | &var->var.VendorGuid); | ||
995 | |||
996 | for (i = 0; i < namelen; i++) | ||
997 | var->var.VariableName[i] = dentry->d_name.name[i]; | ||
998 | |||
999 | var->var.VariableName[i] = '\0'; | ||
1000 | |||
1001 | inode->i_private = var; | ||
1002 | var->efivars = efivars; | ||
1003 | var->kobj.kset = efivars->kset; | ||
1004 | |||
1005 | err = kobject_init_and_add(&var->kobj, &efivar_ktype, NULL, "%s", | ||
1006 | dentry->d_name.name); | ||
1007 | if (err) | ||
1008 | goto out; | ||
1009 | |||
1010 | kobject_uevent(&var->kobj, KOBJ_ADD); | ||
1011 | spin_lock_irq(&efivars->lock); | ||
1012 | list_add(&var->list, &efivars->list); | ||
1013 | spin_unlock_irq(&efivars->lock); | ||
1014 | d_instantiate(dentry, inode); | ||
1015 | dget(dentry); | ||
1016 | out: | ||
1017 | if (err) { | ||
1018 | kfree(var); | ||
1019 | iput(inode); | ||
1020 | } | ||
1021 | return err; | ||
1022 | } | ||
1023 | |||
1024 | static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) | ||
1025 | { | ||
1026 | struct efivar_entry *var = dentry->d_inode->i_private; | ||
1027 | struct efivars *efivars = var->efivars; | ||
1028 | efi_status_t status; | ||
1029 | |||
1030 | spin_lock_irq(&efivars->lock); | ||
1031 | |||
1032 | status = efivars->ops->set_variable(var->var.VariableName, | ||
1033 | &var->var.VendorGuid, | ||
1034 | 0, 0, NULL); | ||
1035 | |||
1036 | if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) { | ||
1037 | list_del(&var->list); | ||
1038 | spin_unlock_irq(&efivars->lock); | ||
1039 | efivar_unregister(var); | ||
1040 | drop_nlink(dentry->d_inode); | ||
1041 | dput(dentry); | ||
1042 | return 0; | ||
1043 | } | ||
1044 | |||
1045 | spin_unlock_irq(&efivars->lock); | ||
1046 | return -EINVAL; | ||
1047 | }; | ||
1048 | |||
1049 | /* | ||
1050 | * Compare two efivarfs file names. | ||
1051 | * | ||
1052 | * An efivarfs filename is composed of two parts, | ||
1053 | * | ||
1054 | * 1. A case-sensitive variable name | ||
1055 | * 2. A case-insensitive GUID | ||
1056 | * | ||
1057 | * So we need to perform a case-sensitive match on part 1 and a | ||
1058 | * case-insensitive match on part 2. | ||
1059 | */ | ||
1060 | static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode, | ||
1061 | const struct dentry *dentry, const struct inode *inode, | ||
1062 | unsigned int len, const char *str, | ||
1063 | const struct qstr *name) | ||
1064 | { | ||
1065 | int guid = len - GUID_LEN; | ||
1066 | |||
1067 | if (name->len != len) | ||
1068 | return 1; | ||
1069 | |||
1070 | /* Case-sensitive compare for the variable name */ | ||
1071 | if (memcmp(str, name->name, guid)) | ||
1072 | return 1; | ||
1073 | |||
1074 | /* Case-insensitive compare for the GUID */ | ||
1075 | return strncasecmp(name->name + guid, str + guid, GUID_LEN); | ||
1076 | } | ||
1077 | |||
1078 | static int efivarfs_d_hash(const struct dentry *dentry, | ||
1079 | const struct inode *inode, struct qstr *qstr) | ||
1080 | { | ||
1081 | unsigned long hash = init_name_hash(); | ||
1082 | const unsigned char *s = qstr->name; | ||
1083 | unsigned int len = qstr->len; | ||
1084 | |||
1085 | if (!efivarfs_valid_name(s, len)) | ||
1086 | return -EINVAL; | ||
1087 | |||
1088 | while (len-- > GUID_LEN) | ||
1089 | hash = partial_name_hash(*s++, hash); | ||
1090 | |||
1091 | /* GUID is case-insensitive. */ | ||
1092 | while (len--) | ||
1093 | hash = partial_name_hash(tolower(*s++), hash); | ||
1094 | |||
1095 | qstr->hash = end_name_hash(hash); | ||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1099 | /* | ||
1100 | * Retaining negative dentries for an in-memory filesystem just wastes | ||
1101 | * memory and lookup time: arrange for them to be deleted immediately. | ||
1102 | */ | ||
1103 | static int efivarfs_delete_dentry(const struct dentry *dentry) | ||
1104 | { | ||
1105 | return 1; | ||
1106 | } | ||
1107 | |||
1108 | static struct dentry_operations efivarfs_d_ops = { | ||
1109 | .d_compare = efivarfs_d_compare, | ||
1110 | .d_hash = efivarfs_d_hash, | ||
1111 | .d_delete = efivarfs_delete_dentry, | ||
1112 | }; | ||
1113 | |||
1114 | static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) | ||
1115 | { | ||
1116 | struct dentry *d; | ||
1117 | struct qstr q; | ||
1118 | int err; | ||
1119 | |||
1120 | q.name = name; | ||
1121 | q.len = strlen(name); | ||
1122 | |||
1123 | err = efivarfs_d_hash(NULL, NULL, &q); | ||
1124 | if (err) | ||
1125 | return ERR_PTR(err); | ||
1126 | |||
1127 | d = d_alloc(parent, &q); | ||
1128 | if (d) | ||
1129 | return d; | ||
1130 | |||
1131 | return ERR_PTR(-ENOMEM); | ||
1132 | } | ||
1133 | |||
1134 | static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | ||
1135 | { | ||
1136 | struct inode *inode = NULL; | ||
1137 | struct dentry *root; | ||
1138 | struct efivar_entry *entry, *n; | ||
1139 | struct efivars *efivars = &__efivars; | ||
1140 | char *name; | ||
1141 | int err = -ENOMEM; | ||
1142 | |||
1143 | efivarfs_sb = sb; | ||
1144 | |||
1145 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
1146 | sb->s_blocksize = PAGE_CACHE_SIZE; | ||
1147 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | ||
1148 | sb->s_magic = EFIVARFS_MAGIC; | ||
1149 | sb->s_op = &efivarfs_ops; | ||
1150 | sb->s_d_op = &efivarfs_d_ops; | ||
1151 | sb->s_time_gran = 1; | ||
1152 | |||
1153 | inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); | ||
1154 | if (!inode) | ||
1155 | return -ENOMEM; | ||
1156 | inode->i_op = &efivarfs_dir_inode_operations; | ||
1157 | |||
1158 | root = d_make_root(inode); | ||
1159 | sb->s_root = root; | ||
1160 | if (!root) | ||
1161 | return -ENOMEM; | ||
1162 | |||
1163 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | ||
1164 | struct dentry *dentry, *root = efivarfs_sb->s_root; | ||
1165 | unsigned long size = 0; | ||
1166 | int len, i; | ||
1167 | |||
1168 | inode = NULL; | ||
1169 | |||
1170 | len = ucs2_strlen(entry->var.VariableName); | ||
1171 | |||
1172 | /* name, plus '-', plus GUID, plus NUL*/ | ||
1173 | name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC); | ||
1174 | if (!name) | ||
1175 | goto fail; | ||
1176 | |||
1177 | for (i = 0; i < len; i++) | ||
1178 | name[i] = entry->var.VariableName[i] & 0xFF; | ||
1179 | |||
1180 | name[len] = '-'; | ||
1181 | |||
1182 | efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); | ||
1183 | |||
1184 | name[len+GUID_LEN+1] = '\0'; | ||
1185 | |||
1186 | inode = efivarfs_get_inode(efivarfs_sb, root->d_inode, | ||
1187 | S_IFREG | 0644, 0); | ||
1188 | if (!inode) | ||
1189 | goto fail_name; | ||
1190 | |||
1191 | dentry = efivarfs_alloc_dentry(root, name); | ||
1192 | if (IS_ERR(dentry)) { | ||
1193 | err = PTR_ERR(dentry); | ||
1194 | goto fail_inode; | ||
1195 | } | ||
1196 | |||
1197 | /* copied by the above to local storage in the dentry. */ | ||
1198 | kfree(name); | ||
1199 | |||
1200 | spin_lock_irq(&efivars->lock); | ||
1201 | efivars->ops->get_variable(entry->var.VariableName, | ||
1202 | &entry->var.VendorGuid, | ||
1203 | &entry->var.Attributes, | ||
1204 | &size, | ||
1205 | NULL); | ||
1206 | spin_unlock_irq(&efivars->lock); | ||
1207 | |||
1208 | mutex_lock(&inode->i_mutex); | ||
1209 | inode->i_private = entry; | ||
1210 | i_size_write(inode, size + sizeof(entry->var.Attributes)); | ||
1211 | mutex_unlock(&inode->i_mutex); | ||
1212 | d_add(dentry, inode); | ||
1213 | } | ||
1214 | |||
1215 | return 0; | ||
1216 | |||
1217 | fail_inode: | ||
1218 | iput(inode); | ||
1219 | fail_name: | ||
1220 | kfree(name); | ||
1221 | fail: | ||
1222 | return err; | ||
1223 | } | ||
1224 | |||
1225 | static struct dentry *efivarfs_mount(struct file_system_type *fs_type, | ||
1226 | int flags, const char *dev_name, void *data) | ||
1227 | { | ||
1228 | return mount_single(fs_type, flags, data, efivarfs_fill_super); | ||
1229 | } | ||
1230 | |||
1231 | static void efivarfs_kill_sb(struct super_block *sb) | ||
1232 | { | ||
1233 | kill_litter_super(sb); | ||
1234 | efivarfs_sb = NULL; | ||
1235 | } | ||
1236 | |||
1237 | static struct file_system_type efivarfs_type = { | ||
1238 | .name = "efivarfs", | ||
1239 | .mount = efivarfs_mount, | ||
1240 | .kill_sb = efivarfs_kill_sb, | ||
1241 | }; | ||
1242 | MODULE_ALIAS_FS("efivarfs"); | ||
1243 | |||
1244 | /* | ||
1245 | * Handle negative dentry. | ||
1246 | */ | ||
1247 | static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry, | ||
1248 | unsigned int flags) | ||
1249 | { | ||
1250 | if (dentry->d_name.len > NAME_MAX) | ||
1251 | return ERR_PTR(-ENAMETOOLONG); | ||
1252 | d_add(dentry, NULL); | ||
1253 | return NULL; | ||
1254 | } | ||
1255 | |||
1256 | static const struct inode_operations efivarfs_dir_inode_operations = { | ||
1257 | .lookup = efivarfs_lookup, | ||
1258 | .unlink = efivarfs_unlink, | ||
1259 | .create = efivarfs_create, | ||
1260 | }; | ||
1261 | |||
1262 | #ifdef CONFIG_EFI_VARS_PSTORE | ||
1263 | |||
1264 | static int efi_pstore_open(struct pstore_info *psi) | ||
1265 | { | ||
1266 | struct efivars *efivars = psi->data; | ||
1267 | |||
1268 | spin_lock_irq(&efivars->lock); | ||
1269 | efivars->walk_entry = list_first_entry(&efivars->list, | ||
1270 | struct efivar_entry, list); | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static int efi_pstore_close(struct pstore_info *psi) | ||
1275 | { | ||
1276 | struct efivars *efivars = psi->data; | ||
1277 | |||
1278 | spin_unlock_irq(&efivars->lock); | ||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | ||
1283 | int *count, struct timespec *timespec, | ||
1284 | char **buf, struct pstore_info *psi) | ||
1285 | { | ||
1286 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | ||
1287 | struct efivars *efivars = psi->data; | ||
1288 | char name[DUMP_NAME_LEN]; | ||
1289 | int i; | ||
1290 | int cnt; | ||
1291 | unsigned int part, size; | ||
1292 | unsigned long time; | ||
1293 | |||
1294 | while (&efivars->walk_entry->list != &efivars->list) { | ||
1295 | if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid, | ||
1296 | vendor)) { | ||
1297 | for (i = 0; i < DUMP_NAME_LEN; i++) { | ||
1298 | name[i] = efivars->walk_entry->var.VariableName[i]; | ||
1299 | } | ||
1300 | if (sscanf(name, "dump-type%u-%u-%d-%lu", | ||
1301 | type, &part, &cnt, &time) == 4) { | ||
1302 | *id = part; | ||
1303 | *count = cnt; | ||
1304 | timespec->tv_sec = time; | ||
1305 | timespec->tv_nsec = 0; | ||
1306 | } else if (sscanf(name, "dump-type%u-%u-%lu", | ||
1307 | type, &part, &time) == 3) { | ||
1308 | /* | ||
1309 | * Check if an old format, | ||
1310 | * which doesn't support holding | ||
1311 | * multiple logs, remains. | ||
1312 | */ | ||
1313 | *id = part; | ||
1314 | *count = 0; | ||
1315 | timespec->tv_sec = time; | ||
1316 | timespec->tv_nsec = 0; | ||
1317 | } else { | ||
1318 | efivars->walk_entry = list_entry( | ||
1319 | efivars->walk_entry->list.next, | ||
1320 | struct efivar_entry, list); | ||
1321 | continue; | ||
1322 | } | ||
1323 | |||
1324 | get_var_data_locked(efivars, &efivars->walk_entry->var); | ||
1325 | size = efivars->walk_entry->var.DataSize; | ||
1326 | *buf = kmalloc(size, GFP_KERNEL); | ||
1327 | if (*buf == NULL) | ||
1328 | return -ENOMEM; | ||
1329 | memcpy(*buf, efivars->walk_entry->var.Data, | ||
1330 | size); | ||
1331 | efivars->walk_entry = list_entry( | ||
1332 | efivars->walk_entry->list.next, | ||
1333 | struct efivar_entry, list); | ||
1334 | return size; | ||
1335 | } | ||
1336 | efivars->walk_entry = list_entry(efivars->walk_entry->list.next, | ||
1337 | struct efivar_entry, list); | ||
1338 | } | ||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1342 | static int efi_pstore_write(enum pstore_type_id type, | ||
1343 | enum kmsg_dump_reason reason, u64 *id, | ||
1344 | unsigned int part, int count, size_t size, | ||
1345 | struct pstore_info *psi) | ||
1346 | { | ||
1347 | char name[DUMP_NAME_LEN]; | ||
1348 | efi_char16_t efi_name[DUMP_NAME_LEN]; | ||
1349 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | ||
1350 | struct efivars *efivars = psi->data; | ||
1351 | int i, ret = 0; | ||
1352 | efi_status_t status = EFI_NOT_FOUND; | ||
1353 | unsigned long flags; | ||
1354 | |||
1355 | if (pstore_cannot_block_path(reason)) { | ||
1356 | /* | ||
1357 | * If the lock is taken by another cpu in non-blocking path, | ||
1358 | * this driver returns without entering firmware to avoid | ||
1359 | * hanging up. | ||
1360 | */ | ||
1361 | if (!spin_trylock_irqsave(&efivars->lock, flags)) | ||
1362 | return -EBUSY; | ||
1363 | } else | ||
1364 | spin_lock_irqsave(&efivars->lock, flags); | ||
1365 | |||
1366 | /* | ||
1367 | * Check if there is a space enough to log. | ||
1368 | * size: a size of logging data | ||
1369 | * DUMP_NAME_LEN * 2: a maximum size of variable name | ||
1370 | */ | ||
1371 | |||
1372 | status = check_var_size_locked(efivars, PSTORE_EFI_ATTRIBUTES, | ||
1373 | size + DUMP_NAME_LEN * 2); | ||
1374 | |||
1375 | if (status) { | ||
1376 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
1377 | *id = part; | ||
1378 | return -ENOSPC; | ||
1379 | } | ||
1380 | |||
1381 | sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count, | ||
1382 | get_seconds()); | ||
1383 | |||
1384 | for (i = 0; i < DUMP_NAME_LEN; i++) | ||
1385 | efi_name[i] = name[i]; | ||
1386 | |||
1387 | efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES, | ||
1388 | size, psi->buf); | ||
1389 | |||
1390 | spin_unlock_irqrestore(&efivars->lock, flags); | ||
1391 | |||
1392 | if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled) | ||
1393 | schedule_work(&efivar_work); | ||
1394 | |||
1395 | *id = part; | ||
1396 | return ret; | ||
1397 | }; | ||
1398 | |||
1399 | static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | ||
1400 | struct timespec time, struct pstore_info *psi) | ||
1401 | { | ||
1402 | char name[DUMP_NAME_LEN]; | ||
1403 | efi_char16_t efi_name[DUMP_NAME_LEN]; | ||
1404 | char name_old[DUMP_NAME_LEN]; | ||
1405 | efi_char16_t efi_name_old[DUMP_NAME_LEN]; | ||
1406 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | ||
1407 | struct efivars *efivars = psi->data; | ||
1408 | struct efivar_entry *entry, *found = NULL; | ||
1409 | int i; | ||
1410 | |||
1411 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, | ||
1412 | time.tv_sec); | ||
1413 | |||
1414 | spin_lock_irq(&efivars->lock); | ||
1415 | |||
1416 | for (i = 0; i < DUMP_NAME_LEN; i++) | ||
1417 | efi_name[i] = name[i]; | ||
1418 | |||
1419 | /* | ||
1420 | * Clean up an entry with the same name | ||
1421 | */ | ||
1422 | |||
1423 | list_for_each_entry(entry, &efivars->list, list) { | ||
1424 | get_var_data_locked(efivars, &entry->var); | ||
1425 | |||
1426 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) | ||
1427 | continue; | ||
1428 | if (ucs2_strncmp(entry->var.VariableName, efi_name, | ||
1429 | ucs2_strlen(efi_name))) { | ||
1430 | /* | ||
1431 | * Check if an old format, | ||
1432 | * which doesn't support holding | ||
1433 | * multiple logs, remains. | ||
1434 | */ | ||
1435 | sprintf(name_old, "dump-type%u-%u-%lu", type, | ||
1436 | (unsigned int)id, time.tv_sec); | ||
1437 | |||
1438 | for (i = 0; i < DUMP_NAME_LEN; i++) | ||
1439 | efi_name_old[i] = name_old[i]; | ||
1440 | |||
1441 | if (ucs2_strncmp(entry->var.VariableName, efi_name_old, | ||
1442 | ucs2_strlen(efi_name_old))) | ||
1443 | continue; | ||
1444 | } | ||
1445 | |||
1446 | /* found */ | ||
1447 | found = entry; | ||
1448 | efivars->ops->set_variable(entry->var.VariableName, | ||
1449 | &entry->var.VendorGuid, | ||
1450 | PSTORE_EFI_ATTRIBUTES, | ||
1451 | 0, NULL); | ||
1452 | break; | ||
1453 | } | ||
1454 | |||
1455 | if (found) | ||
1456 | list_del(&found->list); | ||
1457 | |||
1458 | spin_unlock_irq(&efivars->lock); | ||
1459 | |||
1460 | if (found) | ||
1461 | efivar_unregister(found); | ||
1462 | |||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | static struct pstore_info efi_pstore_info = { | ||
1467 | .owner = THIS_MODULE, | ||
1468 | .name = "efi", | ||
1469 | .open = efi_pstore_open, | ||
1470 | .close = efi_pstore_close, | ||
1471 | .read = efi_pstore_read, | ||
1472 | .write = efi_pstore_write, | ||
1473 | .erase = efi_pstore_erase, | ||
1474 | }; | ||
1475 | |||
1476 | static void efivar_pstore_register(struct efivars *efivars) | ||
1477 | { | ||
1478 | efivars->efi_pstore_info = efi_pstore_info; | ||
1479 | efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); | ||
1480 | if (efivars->efi_pstore_info.buf) { | ||
1481 | efivars->efi_pstore_info.bufsize = 1024; | ||
1482 | efivars->efi_pstore_info.data = efivars; | ||
1483 | spin_lock_init(&efivars->efi_pstore_info.buf_lock); | ||
1484 | pstore_register(&efivars->efi_pstore_info); | ||
1485 | } | ||
1486 | } | ||
1487 | #else | ||
1488 | static void efivar_pstore_register(struct efivars *efivars) | ||
1489 | { | ||
1490 | return; | ||
1491 | } | ||
1492 | #endif | ||
1493 | |||
1494 | static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | ||
1495 | struct bin_attribute *bin_attr, | ||
1496 | char *buf, loff_t pos, size_t count) | ||
1497 | { | ||
1498 | struct efi_variable *new_var = (struct efi_variable *)buf; | ||
1499 | struct efivars *efivars = bin_attr->private; | ||
1500 | struct efivar_entry *search_efivar, *n; | ||
1501 | unsigned long strsize1, strsize2; | ||
1502 | efi_status_t status = EFI_NOT_FOUND; | ||
1503 | int found = 0; | ||
1504 | |||
1505 | if (!capable(CAP_SYS_ADMIN)) | ||
1506 | return -EACCES; | ||
1507 | |||
1508 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
1509 | validate_var(new_var, new_var->Data, new_var->DataSize) == false) { | ||
1510 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
1511 | return -EINVAL; | ||
1512 | } | ||
1513 | |||
1514 | spin_lock_irq(&efivars->lock); | ||
1515 | |||
1516 | /* | ||
1517 | * Does this variable already exist? | ||
1518 | */ | ||
1519 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | ||
1520 | strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024); | ||
1521 | strsize2 = ucs2_strsize(new_var->VariableName, 1024); | ||
1522 | if (strsize1 == strsize2 && | ||
1523 | !memcmp(&(search_efivar->var.VariableName), | ||
1524 | new_var->VariableName, strsize1) && | ||
1525 | !efi_guidcmp(search_efivar->var.VendorGuid, | ||
1526 | new_var->VendorGuid)) { | ||
1527 | found = 1; | ||
1528 | break; | ||
1529 | } | ||
1530 | } | ||
1531 | if (found) { | ||
1532 | spin_unlock_irq(&efivars->lock); | ||
1533 | return -EINVAL; | ||
1534 | } | ||
1535 | |||
1536 | status = check_var_size_locked(efivars, new_var->Attributes, | ||
1537 | new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024)); | ||
1538 | |||
1539 | if (status && status != EFI_UNSUPPORTED) { | ||
1540 | spin_unlock_irq(&efivars->lock); | ||
1541 | return efi_status_to_err(status); | ||
1542 | } | ||
1543 | |||
1544 | /* now *really* create the variable via EFI */ | ||
1545 | status = efivars->ops->set_variable(new_var->VariableName, | ||
1546 | &new_var->VendorGuid, | ||
1547 | new_var->Attributes, | ||
1548 | new_var->DataSize, | ||
1549 | new_var->Data); | ||
1550 | |||
1551 | if (status != EFI_SUCCESS) { | ||
1552 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | ||
1553 | status); | ||
1554 | spin_unlock_irq(&efivars->lock); | ||
1555 | return -EIO; | ||
1556 | } | ||
1557 | spin_unlock_irq(&efivars->lock); | ||
1558 | |||
1559 | /* Create the entry in sysfs. Locking is not required here */ | ||
1560 | status = efivar_create_sysfs_entry(efivars, | ||
1561 | ucs2_strsize(new_var->VariableName, | ||
1562 | 1024), | ||
1563 | new_var->VariableName, | ||
1564 | &new_var->VendorGuid); | ||
1565 | if (status) { | ||
1566 | printk(KERN_WARNING "efivars: variable created, but sysfs entry wasn't.\n"); | ||
1567 | } | ||
1568 | return count; | ||
1569 | } | ||
1570 | |||
1571 | static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | ||
1572 | struct bin_attribute *bin_attr, | ||
1573 | char *buf, loff_t pos, size_t count) | ||
1574 | { | ||
1575 | struct efi_variable *del_var = (struct efi_variable *)buf; | ||
1576 | struct efivars *efivars = bin_attr->private; | ||
1577 | struct efivar_entry *search_efivar, *n; | ||
1578 | unsigned long strsize1, strsize2; | ||
1579 | efi_status_t status = EFI_NOT_FOUND; | ||
1580 | int found = 0; | ||
1581 | |||
1582 | if (!capable(CAP_SYS_ADMIN)) | ||
1583 | return -EACCES; | ||
1584 | |||
1585 | spin_lock_irq(&efivars->lock); | ||
1586 | |||
1587 | /* | ||
1588 | * Does this variable already exist? | ||
1589 | */ | ||
1590 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | ||
1591 | strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024); | ||
1592 | strsize2 = ucs2_strsize(del_var->VariableName, 1024); | ||
1593 | if (strsize1 == strsize2 && | ||
1594 | !memcmp(&(search_efivar->var.VariableName), | ||
1595 | del_var->VariableName, strsize1) && | ||
1596 | !efi_guidcmp(search_efivar->var.VendorGuid, | ||
1597 | del_var->VendorGuid)) { | ||
1598 | found = 1; | ||
1599 | break; | ||
1600 | } | ||
1601 | } | ||
1602 | if (!found) { | ||
1603 | spin_unlock_irq(&efivars->lock); | ||
1604 | return -EINVAL; | ||
1605 | } | ||
1606 | /* force the Attributes/DataSize to 0 to ensure deletion */ | ||
1607 | del_var->Attributes = 0; | ||
1608 | del_var->DataSize = 0; | ||
1609 | |||
1610 | status = efivars->ops->set_variable(del_var->VariableName, | ||
1611 | &del_var->VendorGuid, | ||
1612 | del_var->Attributes, | ||
1613 | del_var->DataSize, | ||
1614 | del_var->Data); | ||
1615 | |||
1616 | if (status != EFI_SUCCESS) { | ||
1617 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | ||
1618 | status); | ||
1619 | spin_unlock_irq(&efivars->lock); | ||
1620 | return -EIO; | ||
1621 | } | ||
1622 | list_del(&search_efivar->list); | ||
1623 | /* We need to release this lock before unregistering. */ | ||
1624 | spin_unlock_irq(&efivars->lock); | ||
1625 | efivar_unregister(search_efivar); | ||
1626 | |||
1627 | /* It's dead Jim.... */ | ||
1628 | return count; | ||
1629 | } | ||
1630 | |||
1631 | static bool variable_is_present(struct efivars *efivars, | ||
1632 | efi_char16_t *variable_name, | ||
1633 | efi_guid_t *vendor) | ||
1634 | { | ||
1635 | struct efivar_entry *entry, *n; | ||
1636 | unsigned long strsize1, strsize2; | ||
1637 | bool found = false; | ||
1638 | |||
1639 | strsize1 = ucs2_strsize(variable_name, 1024); | ||
1640 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | ||
1641 | strsize2 = ucs2_strsize(entry->var.VariableName, 1024); | ||
1642 | if (strsize1 == strsize2 && | ||
1643 | !memcmp(variable_name, &(entry->var.VariableName), | ||
1644 | strsize2) && | ||
1645 | !efi_guidcmp(entry->var.VendorGuid, | ||
1646 | *vendor)) { | ||
1647 | found = true; | ||
1648 | break; | ||
1649 | } | ||
1650 | } | ||
1651 | return found; | ||
1652 | } | ||
1653 | |||
1654 | /* | ||
1655 | * Returns the size of variable_name, in bytes, including the | ||
1656 | * terminating NULL character, or variable_name_size if no NULL | ||
1657 | * character is found among the first variable_name_size bytes. | ||
1658 | */ | ||
1659 | static unsigned long var_name_strnsize(efi_char16_t *variable_name, | ||
1660 | unsigned long variable_name_size) | ||
1661 | { | ||
1662 | unsigned long len; | ||
1663 | efi_char16_t c; | ||
1664 | |||
1665 | /* | ||
1666 | * The variable name is, by definition, a NULL-terminated | ||
1667 | * string, so make absolutely sure that variable_name_size is | ||
1668 | * the value we expect it to be. If not, return the real size. | ||
1669 | */ | ||
1670 | for (len = 2; len <= variable_name_size; len += sizeof(c)) { | ||
1671 | c = variable_name[(len / sizeof(c)) - 1]; | ||
1672 | if (!c) | ||
1673 | break; | ||
1674 | } | ||
1675 | |||
1676 | return min(len, variable_name_size); | ||
1677 | } | ||
1678 | |||
1679 | static void efivar_update_sysfs_entries(struct work_struct *work) | ||
1680 | { | ||
1681 | struct efivars *efivars = &__efivars; | ||
1682 | efi_guid_t vendor; | ||
1683 | efi_char16_t *variable_name; | ||
1684 | unsigned long variable_name_size = 1024; | ||
1685 | efi_status_t status = EFI_NOT_FOUND; | ||
1686 | bool found; | ||
1687 | |||
1688 | /* Add new sysfs entries */ | ||
1689 | while (1) { | ||
1690 | variable_name = kzalloc(variable_name_size, GFP_KERNEL); | ||
1691 | if (!variable_name) { | ||
1692 | pr_err("efivars: Memory allocation failed.\n"); | ||
1693 | return; | ||
1694 | } | ||
1695 | |||
1696 | spin_lock_irq(&efivars->lock); | ||
1697 | found = false; | ||
1698 | while (1) { | ||
1699 | variable_name_size = 1024; | ||
1700 | status = efivars->ops->get_next_variable( | ||
1701 | &variable_name_size, | ||
1702 | variable_name, | ||
1703 | &vendor); | ||
1704 | if (status != EFI_SUCCESS) { | ||
1705 | break; | ||
1706 | } else { | ||
1707 | if (!variable_is_present(efivars, | ||
1708 | variable_name, &vendor)) { | ||
1709 | found = true; | ||
1710 | break; | ||
1711 | } | ||
1712 | } | ||
1713 | } | ||
1714 | spin_unlock_irq(&efivars->lock); | ||
1715 | |||
1716 | if (!found) { | ||
1717 | kfree(variable_name); | ||
1718 | break; | ||
1719 | } else { | ||
1720 | variable_name_size = var_name_strnsize(variable_name, | ||
1721 | variable_name_size); | ||
1722 | efivar_create_sysfs_entry(efivars, | ||
1723 | variable_name_size, | ||
1724 | variable_name, &vendor); | ||
1725 | } | ||
1726 | } | ||
1727 | } | ||
1728 | |||
1729 | /* | ||
1730 | * Let's not leave out systab information that snuck into | ||
1731 | * the efivars driver | ||
1732 | */ | ||
1733 | static ssize_t systab_show(struct kobject *kobj, | ||
1734 | struct kobj_attribute *attr, char *buf) | ||
1735 | { | ||
1736 | char *str = buf; | ||
1737 | |||
1738 | if (!kobj || !buf) | ||
1739 | return -EINVAL; | ||
1740 | |||
1741 | if (efi.mps != EFI_INVALID_TABLE_ADDR) | ||
1742 | str += sprintf(str, "MPS=0x%lx\n", efi.mps); | ||
1743 | if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) | ||
1744 | str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20); | ||
1745 | if (efi.acpi != EFI_INVALID_TABLE_ADDR) | ||
1746 | str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); | ||
1747 | if (efi.smbios != EFI_INVALID_TABLE_ADDR) | ||
1748 | str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); | ||
1749 | if (efi.hcdp != EFI_INVALID_TABLE_ADDR) | ||
1750 | str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); | ||
1751 | if (efi.boot_info != EFI_INVALID_TABLE_ADDR) | ||
1752 | str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info); | ||
1753 | if (efi.uga != EFI_INVALID_TABLE_ADDR) | ||
1754 | str += sprintf(str, "UGA=0x%lx\n", efi.uga); | ||
1755 | |||
1756 | return str - buf; | ||
1757 | } | ||
1758 | |||
1759 | static struct kobj_attribute efi_attr_systab = | ||
1760 | __ATTR(systab, 0400, systab_show, NULL); | ||
1761 | |||
1762 | static struct attribute *efi_subsys_attrs[] = { | ||
1763 | &efi_attr_systab.attr, | ||
1764 | NULL, /* maybe more in the future? */ | ||
1765 | }; | ||
1766 | |||
1767 | static struct attribute_group efi_subsys_attr_group = { | ||
1768 | .attrs = efi_subsys_attrs, | ||
1769 | }; | ||
1770 | |||
1771 | static struct kobject *efi_kobj; | ||
1772 | |||
1773 | /* | ||
1774 | * efivar_create_sysfs_entry() | ||
1775 | * Requires: | ||
1776 | * variable_name_size = number of bytes required to hold | ||
1777 | * variable_name (not counting the NULL | ||
1778 | * character at the end. | ||
1779 | * efivars->lock is not held on entry or exit. | ||
1780 | * Returns 1 on failure, 0 on success | ||
1781 | */ | ||
1782 | static int | ||
1783 | efivar_create_sysfs_entry(struct efivars *efivars, | ||
1784 | unsigned long variable_name_size, | ||
1785 | efi_char16_t *variable_name, | ||
1786 | efi_guid_t *vendor_guid) | ||
1787 | { | ||
1788 | int i, short_name_size; | ||
1789 | char *short_name; | ||
1790 | struct efivar_entry *new_efivar; | ||
1791 | |||
1792 | /* | ||
1793 | * Length of the variable bytes in ASCII, plus the '-' separator, | ||
1794 | * plus the GUID, plus trailing NUL | ||
1795 | */ | ||
1796 | short_name_size = variable_name_size / sizeof(efi_char16_t) | ||
1797 | + 1 + GUID_LEN + 1; | ||
1798 | |||
1799 | short_name = kzalloc(short_name_size, GFP_KERNEL); | ||
1800 | new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); | ||
1801 | |||
1802 | if (!short_name || !new_efivar) { | ||
1803 | kfree(short_name); | ||
1804 | kfree(new_efivar); | ||
1805 | return 1; | ||
1806 | } | ||
1807 | |||
1808 | new_efivar->efivars = efivars; | ||
1809 | memcpy(new_efivar->var.VariableName, variable_name, | ||
1810 | variable_name_size); | ||
1811 | memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t)); | ||
1812 | |||
1813 | /* Convert Unicode to normal chars (assume top bits are 0), | ||
1814 | ala UTF-8 */ | ||
1815 | for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { | ||
1816 | short_name[i] = variable_name[i] & 0xFF; | ||
1817 | } | ||
1818 | /* This is ugly, but necessary to separate one vendor's | ||
1819 | private variables from another's. */ | ||
1820 | |||
1821 | *(short_name + strlen(short_name)) = '-'; | ||
1822 | efi_guid_unparse(vendor_guid, short_name + strlen(short_name)); | ||
1823 | |||
1824 | new_efivar->kobj.kset = efivars->kset; | ||
1825 | i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL, | ||
1826 | "%s", short_name); | ||
1827 | if (i) { | ||
1828 | kfree(short_name); | ||
1829 | kfree(new_efivar); | ||
1830 | return 1; | ||
1831 | } | ||
1832 | |||
1833 | kobject_uevent(&new_efivar->kobj, KOBJ_ADD); | ||
1834 | kfree(short_name); | ||
1835 | short_name = NULL; | ||
1836 | |||
1837 | spin_lock_irq(&efivars->lock); | ||
1838 | list_add(&new_efivar->list, &efivars->list); | ||
1839 | spin_unlock_irq(&efivars->lock); | ||
1840 | |||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | static int | ||
1845 | create_efivars_bin_attributes(struct efivars *efivars) | ||
1846 | { | ||
1847 | struct bin_attribute *attr; | ||
1848 | int error; | ||
1849 | |||
1850 | /* new_var */ | ||
1851 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
1852 | if (!attr) | ||
1853 | return -ENOMEM; | ||
1854 | |||
1855 | attr->attr.name = "new_var"; | ||
1856 | attr->attr.mode = 0200; | ||
1857 | attr->write = efivar_create; | ||
1858 | attr->private = efivars; | ||
1859 | efivars->new_var = attr; | ||
1860 | |||
1861 | /* del_var */ | ||
1862 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
1863 | if (!attr) { | ||
1864 | error = -ENOMEM; | ||
1865 | goto out_free; | ||
1866 | } | ||
1867 | attr->attr.name = "del_var"; | ||
1868 | attr->attr.mode = 0200; | ||
1869 | attr->write = efivar_delete; | ||
1870 | attr->private = efivars; | ||
1871 | efivars->del_var = attr; | ||
1872 | |||
1873 | sysfs_bin_attr_init(efivars->new_var); | ||
1874 | sysfs_bin_attr_init(efivars->del_var); | ||
1875 | |||
1876 | /* Register */ | ||
1877 | error = sysfs_create_bin_file(&efivars->kset->kobj, | ||
1878 | efivars->new_var); | ||
1879 | if (error) { | ||
1880 | printk(KERN_ERR "efivars: unable to create new_var sysfs file" | ||
1881 | " due to error %d\n", error); | ||
1882 | goto out_free; | ||
1883 | } | ||
1884 | error = sysfs_create_bin_file(&efivars->kset->kobj, | ||
1885 | efivars->del_var); | ||
1886 | if (error) { | ||
1887 | printk(KERN_ERR "efivars: unable to create del_var sysfs file" | ||
1888 | " due to error %d\n", error); | ||
1889 | sysfs_remove_bin_file(&efivars->kset->kobj, | ||
1890 | efivars->new_var); | ||
1891 | goto out_free; | ||
1892 | } | ||
1893 | |||
1894 | return 0; | ||
1895 | out_free: | ||
1896 | kfree(efivars->del_var); | ||
1897 | efivars->del_var = NULL; | ||
1898 | kfree(efivars->new_var); | ||
1899 | efivars->new_var = NULL; | ||
1900 | return error; | ||
1901 | } | ||
1902 | |||
1903 | void unregister_efivars(struct efivars *efivars) | ||
1904 | { | ||
1905 | struct efivar_entry *entry, *n; | ||
1906 | |||
1907 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | ||
1908 | spin_lock_irq(&efivars->lock); | ||
1909 | list_del(&entry->list); | ||
1910 | spin_unlock_irq(&efivars->lock); | ||
1911 | efivar_unregister(entry); | ||
1912 | } | ||
1913 | if (efivars->new_var) | ||
1914 | sysfs_remove_bin_file(&efivars->kset->kobj, efivars->new_var); | ||
1915 | if (efivars->del_var) | ||
1916 | sysfs_remove_bin_file(&efivars->kset->kobj, efivars->del_var); | ||
1917 | kfree(efivars->new_var); | ||
1918 | kfree(efivars->del_var); | ||
1919 | kobject_put(efivars->kobject); | ||
1920 | kset_unregister(efivars->kset); | ||
1921 | } | ||
1922 | EXPORT_SYMBOL_GPL(unregister_efivars); | ||
1923 | |||
1924 | /* | ||
1925 | * Print a warning when duplicate EFI variables are encountered and | ||
1926 | * disable the sysfs workqueue since the firmware is buggy. | ||
1927 | */ | ||
1928 | static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | ||
1929 | unsigned long len16) | ||
1930 | { | ||
1931 | size_t i, len8 = len16 / sizeof(efi_char16_t); | ||
1932 | char *s8; | ||
1933 | |||
1934 | /* | ||
1935 | * Disable the workqueue since the algorithm it uses for | ||
1936 | * detecting new variables won't work with this buggy | ||
1937 | * implementation of GetNextVariableName(). | ||
1938 | */ | ||
1939 | efivar_wq_enabled = false; | ||
1940 | |||
1941 | s8 = kzalloc(len8, GFP_KERNEL); | ||
1942 | if (!s8) | ||
1943 | return; | ||
1944 | |||
1945 | for (i = 0; i < len8; i++) | ||
1946 | s8[i] = s16[i]; | ||
1947 | |||
1948 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", | ||
1949 | s8, vendor_guid); | ||
1950 | kfree(s8); | ||
1951 | } | ||
1952 | |||
1953 | int register_efivars(struct efivars *efivars, | ||
1954 | const struct efivar_operations *ops, | ||
1955 | struct kobject *parent_kobj) | ||
1956 | { | ||
1957 | efi_status_t status = EFI_NOT_FOUND; | ||
1958 | efi_guid_t vendor_guid; | ||
1959 | efi_char16_t *variable_name; | ||
1960 | unsigned long variable_name_size = 1024; | ||
1961 | int error = 0; | ||
1962 | |||
1963 | variable_name = kzalloc(variable_name_size, GFP_KERNEL); | ||
1964 | if (!variable_name) { | ||
1965 | printk(KERN_ERR "efivars: Memory allocation failed.\n"); | ||
1966 | return -ENOMEM; | ||
1967 | } | ||
1968 | |||
1969 | spin_lock_init(&efivars->lock); | ||
1970 | INIT_LIST_HEAD(&efivars->list); | ||
1971 | efivars->ops = ops; | ||
1972 | |||
1973 | efivars->kset = kset_create_and_add("vars", NULL, parent_kobj); | ||
1974 | if (!efivars->kset) { | ||
1975 | printk(KERN_ERR "efivars: Subsystem registration failed.\n"); | ||
1976 | error = -ENOMEM; | ||
1977 | goto out; | ||
1978 | } | ||
1979 | |||
1980 | efivars->kobject = kobject_create_and_add("efivars", parent_kobj); | ||
1981 | if (!efivars->kobject) { | ||
1982 | pr_err("efivars: Subsystem registration failed.\n"); | ||
1983 | error = -ENOMEM; | ||
1984 | kset_unregister(efivars->kset); | ||
1985 | goto out; | ||
1986 | } | ||
1987 | |||
1988 | /* | ||
1989 | * Per EFI spec, the maximum storage allocated for both | ||
1990 | * the variable name and variable data is 1024 bytes. | ||
1991 | */ | ||
1992 | |||
1993 | do { | ||
1994 | variable_name_size = 1024; | ||
1995 | |||
1996 | status = ops->get_next_variable(&variable_name_size, | ||
1997 | variable_name, | ||
1998 | &vendor_guid); | ||
1999 | switch (status) { | ||
2000 | case EFI_SUCCESS: | ||
2001 | variable_name_size = var_name_strnsize(variable_name, | ||
2002 | variable_name_size); | ||
2003 | |||
2004 | /* | ||
2005 | * Some firmware implementations return the | ||
2006 | * same variable name on multiple calls to | ||
2007 | * get_next_variable(). Terminate the loop | ||
2008 | * immediately as there is no guarantee that | ||
2009 | * we'll ever see a different variable name, | ||
2010 | * and may end up looping here forever. | ||
2011 | */ | ||
2012 | if (variable_is_present(efivars, variable_name, | ||
2013 | &vendor_guid)) { | ||
2014 | dup_variable_bug(variable_name, &vendor_guid, | ||
2015 | variable_name_size); | ||
2016 | status = EFI_NOT_FOUND; | ||
2017 | break; | ||
2018 | } | ||
2019 | |||
2020 | efivar_create_sysfs_entry(efivars, | ||
2021 | variable_name_size, | ||
2022 | variable_name, | ||
2023 | &vendor_guid); | ||
2024 | break; | ||
2025 | case EFI_NOT_FOUND: | ||
2026 | break; | ||
2027 | default: | ||
2028 | printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n", | ||
2029 | status); | ||
2030 | status = EFI_NOT_FOUND; | ||
2031 | break; | ||
2032 | } | ||
2033 | } while (status != EFI_NOT_FOUND); | ||
2034 | |||
2035 | error = create_efivars_bin_attributes(efivars); | ||
2036 | if (error) | ||
2037 | unregister_efivars(efivars); | ||
2038 | |||
2039 | if (!efivars_pstore_disable) | ||
2040 | efivar_pstore_register(efivars); | ||
2041 | |||
2042 | register_filesystem(&efivarfs_type); | ||
2043 | |||
2044 | out: | ||
2045 | kfree(variable_name); | ||
2046 | |||
2047 | return error; | ||
2048 | } | ||
2049 | EXPORT_SYMBOL_GPL(register_efivars); | ||
2050 | |||
2051 | /* | ||
2052 | * For now we register the efi subsystem with the firmware subsystem | ||
2053 | * and the vars subsystem with the efi subsystem. In the future, it | ||
2054 | * might make sense to split off the efi subsystem into its own | ||
2055 | * driver, but for now only efivars will register with it, so just | ||
2056 | * include it here. | ||
2057 | */ | ||
2058 | |||
2059 | static int __init | ||
2060 | efivars_init(void) | ||
2061 | { | ||
2062 | int error = 0; | ||
2063 | |||
2064 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, | ||
2065 | EFIVARS_DATE); | ||
2066 | |||
2067 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) | ||
2068 | return 0; | ||
2069 | |||
2070 | /* For now we'll register the efi directory at /sys/firmware/efi */ | ||
2071 | efi_kobj = kobject_create_and_add("efi", firmware_kobj); | ||
2072 | if (!efi_kobj) { | ||
2073 | printk(KERN_ERR "efivars: Firmware registration failed.\n"); | ||
2074 | return -ENOMEM; | ||
2075 | } | ||
2076 | |||
2077 | ops.get_variable = efi.get_variable; | ||
2078 | ops.set_variable = efi.set_variable; | ||
2079 | ops.get_next_variable = efi.get_next_variable; | ||
2080 | ops.query_variable_store = efi_query_variable_store; | ||
2081 | |||
2082 | error = register_efivars(&__efivars, &ops, efi_kobj); | ||
2083 | if (error) | ||
2084 | goto err_put; | ||
2085 | |||
2086 | /* Don't forget the systab entry */ | ||
2087 | error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); | ||
2088 | if (error) { | ||
2089 | printk(KERN_ERR | ||
2090 | "efivars: Sysfs attribute export failed with error %d.\n", | ||
2091 | error); | ||
2092 | goto err_unregister; | ||
2093 | } | ||
2094 | |||
2095 | return 0; | ||
2096 | |||
2097 | err_unregister: | ||
2098 | unregister_efivars(&__efivars); | ||
2099 | err_put: | ||
2100 | kobject_put(efi_kobj); | ||
2101 | return error; | ||
2102 | } | ||
2103 | |||
2104 | static void __exit | ||
2105 | efivars_exit(void) | ||
2106 | { | ||
2107 | cancel_work_sync(&efivar_work); | ||
2108 | |||
2109 | if (efi_enabled(EFI_RUNTIME_SERVICES)) { | ||
2110 | unregister_efivars(&__efivars); | ||
2111 | kobject_put(efi_kobj); | ||
2112 | } | ||
2113 | } | ||
2114 | |||
2115 | module_init(efivars_init); | ||
2116 | module_exit(efivars_exit); | ||
2117 | |||
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index 91ddf0f7a1b9..acba0b9f4406 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/reboot.h> | 28 | #include <linux/reboot.h> |
29 | #include <linux/efi.h> | 29 | #include <linux/efi.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/ucs2_string.h> | ||
31 | 32 | ||
32 | #define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */ | 33 | #define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */ |
33 | /* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */ | 34 | /* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */ |
@@ -288,17 +289,6 @@ static int gsmi_exec(u8 func, u8 sub) | |||
288 | return rc; | 289 | return rc; |
289 | } | 290 | } |
290 | 291 | ||
291 | /* Return the number of unicode characters in data */ | ||
292 | static size_t | ||
293 | utf16_strlen(efi_char16_t *data, unsigned long maxlength) | ||
294 | { | ||
295 | unsigned long length = 0; | ||
296 | |||
297 | while (*data++ != 0 && length < maxlength) | ||
298 | length++; | ||
299 | return length; | ||
300 | } | ||
301 | |||
302 | static efi_status_t gsmi_get_variable(efi_char16_t *name, | 292 | static efi_status_t gsmi_get_variable(efi_char16_t *name, |
303 | efi_guid_t *vendor, u32 *attr, | 293 | efi_guid_t *vendor, u32 *attr, |
304 | unsigned long *data_size, | 294 | unsigned long *data_size, |
@@ -311,7 +301,7 @@ static efi_status_t gsmi_get_variable(efi_char16_t *name, | |||
311 | }; | 301 | }; |
312 | efi_status_t ret = EFI_SUCCESS; | 302 | efi_status_t ret = EFI_SUCCESS; |
313 | unsigned long flags; | 303 | unsigned long flags; |
314 | size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2); | 304 | size_t name_len = ucs2_strnlen(name, GSMI_BUF_SIZE / 2); |
315 | int rc; | 305 | int rc; |
316 | 306 | ||
317 | if (name_len >= GSMI_BUF_SIZE / 2) | 307 | if (name_len >= GSMI_BUF_SIZE / 2) |
@@ -380,7 +370,7 @@ static efi_status_t gsmi_get_next_variable(unsigned long *name_size, | |||
380 | return EFI_BAD_BUFFER_SIZE; | 370 | return EFI_BAD_BUFFER_SIZE; |
381 | 371 | ||
382 | /* Let's make sure the thing is at least null-terminated */ | 372 | /* Let's make sure the thing is at least null-terminated */ |
383 | if (utf16_strlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2) | 373 | if (ucs2_strnlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2) |
384 | return EFI_INVALID_PARAMETER; | 374 | return EFI_INVALID_PARAMETER; |
385 | 375 | ||
386 | spin_lock_irqsave(&gsmi_dev.lock, flags); | 376 | spin_lock_irqsave(&gsmi_dev.lock, flags); |
@@ -408,7 +398,7 @@ static efi_status_t gsmi_get_next_variable(unsigned long *name_size, | |||
408 | 398 | ||
409 | /* Copy the name back */ | 399 | /* Copy the name back */ |
410 | memcpy(name, gsmi_dev.name_buf->start, GSMI_BUF_SIZE); | 400 | memcpy(name, gsmi_dev.name_buf->start, GSMI_BUF_SIZE); |
411 | *name_size = utf16_strlen(name, GSMI_BUF_SIZE / 2) * 2; | 401 | *name_size = ucs2_strnlen(name, GSMI_BUF_SIZE / 2) * 2; |
412 | 402 | ||
413 | /* copy guid to return buffer */ | 403 | /* copy guid to return buffer */ |
414 | memcpy(vendor, ¶m.guid, sizeof(param.guid)); | 404 | memcpy(vendor, ¶m.guid, sizeof(param.guid)); |
@@ -434,7 +424,7 @@ static efi_status_t gsmi_set_variable(efi_char16_t *name, | |||
434 | EFI_VARIABLE_BOOTSERVICE_ACCESS | | 424 | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
435 | EFI_VARIABLE_RUNTIME_ACCESS, | 425 | EFI_VARIABLE_RUNTIME_ACCESS, |
436 | }; | 426 | }; |
437 | size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2); | 427 | size_t name_len = ucs2_strnlen(name, GSMI_BUF_SIZE / 2); |
438 | efi_status_t ret = EFI_SUCCESS; | 428 | efi_status_t ret = EFI_SUCCESS; |
439 | int rc; | 429 | int rc; |
440 | unsigned long flags; | 430 | unsigned long flags; |
@@ -893,12 +883,19 @@ static __init int gsmi_init(void) | |||
893 | goto out_remove_bin_file; | 883 | goto out_remove_bin_file; |
894 | } | 884 | } |
895 | 885 | ||
896 | ret = register_efivars(&efivars, &efivar_ops, gsmi_kobj); | 886 | ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj); |
897 | if (ret) { | 887 | if (ret) { |
898 | printk(KERN_INFO "gsmi: Failed to register efivars\n"); | 888 | printk(KERN_INFO "gsmi: Failed to register efivars\n"); |
899 | goto out_remove_sysfs_files; | 889 | goto out_remove_sysfs_files; |
900 | } | 890 | } |
901 | 891 | ||
892 | ret = efivars_sysfs_init(); | ||
893 | if (ret) { | ||
894 | printk(KERN_INFO "gsmi: Failed to create efivars files\n"); | ||
895 | efivars_unregister(&efivars); | ||
896 | goto out_remove_sysfs_files; | ||
897 | } | ||
898 | |||
902 | register_reboot_notifier(&gsmi_reboot_notifier); | 899 | register_reboot_notifier(&gsmi_reboot_notifier); |
903 | register_die_notifier(&gsmi_die_notifier); | 900 | register_die_notifier(&gsmi_die_notifier); |
904 | atomic_notifier_chain_register(&panic_notifier_list, | 901 | atomic_notifier_chain_register(&panic_notifier_list, |
@@ -930,7 +927,7 @@ static void __exit gsmi_exit(void) | |||
930 | unregister_die_notifier(&gsmi_die_notifier); | 927 | unregister_die_notifier(&gsmi_die_notifier); |
931 | atomic_notifier_chain_unregister(&panic_notifier_list, | 928 | atomic_notifier_chain_unregister(&panic_notifier_list, |
932 | &gsmi_panic_notifier); | 929 | &gsmi_panic_notifier); |
933 | unregister_efivars(&efivars); | 930 | efivars_unregister(&efivars); |
934 | 931 | ||
935 | sysfs_remove_files(gsmi_kobj, gsmi_attrs); | 932 | sysfs_remove_files(gsmi_kobj, gsmi_attrs); |
936 | sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); | 933 | sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr); |