diff options
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rw-r--r-- | drivers/firmware/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/efi/Makefile | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 134 | ||||
-rw-r--r-- | drivers/firmware/efi/efivars.c | 617 | ||||
-rw-r--r-- | drivers/firmware/efi/vars.c (renamed from drivers/firmware/efivars.c) | 769 | ||||
-rw-r--r-- | fs/efivarfs/Kconfig | 2 | ||||
-rw-r--r-- | include/linux/efi.h | 3 |
8 files changed, 769 insertions, 761 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 0855f4450e91..e0cd7e53acc0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2987,7 +2987,7 @@ F: arch/ia64/kernel/efi.c | |||
2987 | F: arch/x86/boot/compressed/eboot.[ch] | 2987 | F: arch/x86/boot/compressed/eboot.[ch] |
2988 | F: arch/x86/include/asm/efi.h | 2988 | F: arch/x86/include/asm/efi.h |
2989 | F: arch/x86/platform/efi/* | 2989 | F: arch/x86/platform/efi/* |
2990 | F: drivers/firmware/efivars.c | 2990 | F: drivers/firmware/efi/* |
2991 | F: include/linux/efi*.h | 2991 | F: include/linux/efi*.h |
2992 | 2992 | ||
2993 | EFI VARIABLE FILESYSTEM | 2993 | EFI VARIABLE FILESYSTEM |
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 31bf68c93593..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 |
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index e03cd51525c2..99245ab5a79c 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile | |||
@@ -1,4 +1,6 @@ | |||
1 | # | 1 | # |
2 | # Makefile for linux kernel | 2 | # Makefile for linux kernel |
3 | # | 3 | # |
4 | obj-y += efi.o vars.o | ||
5 | obj-$(CONFIG_EFI_VARS) += efivars.o | ||
4 | obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o | 6 | obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c new file mode 100644 index 000000000000..32bdf4f8e432 --- /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_info = efi.query_variable_info; | ||
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..70635b3b59d3 --- /dev/null +++ b/drivers/firmware/efi/efivars.c | |||
@@ -0,0 +1,617 @@ | |||
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 | |||
71 | #define EFIVARS_VERSION "0.08" | ||
72 | #define EFIVARS_DATE "2004-May-17" | ||
73 | |||
74 | MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); | ||
75 | MODULE_DESCRIPTION("sysfs interface to EFI Variables"); | ||
76 | MODULE_LICENSE("GPL"); | ||
77 | MODULE_VERSION(EFIVARS_VERSION); | ||
78 | |||
79 | LIST_HEAD(efivar_sysfs_list); | ||
80 | EXPORT_SYMBOL_GPL(efivar_sysfs_list); | ||
81 | |||
82 | static struct kset *efivars_kset; | ||
83 | |||
84 | static struct bin_attribute *efivars_new_var; | ||
85 | static struct bin_attribute *efivars_del_var; | ||
86 | |||
87 | struct efivar_attribute { | ||
88 | struct attribute attr; | ||
89 | ssize_t (*show) (struct efivar_entry *entry, char *buf); | ||
90 | ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); | ||
91 | }; | ||
92 | |||
93 | #define EFIVAR_ATTR(_name, _mode, _show, _store) \ | ||
94 | struct efivar_attribute efivar_attr_##_name = { \ | ||
95 | .attr = {.name = __stringify(_name), .mode = _mode}, \ | ||
96 | .show = _show, \ | ||
97 | .store = _store, \ | ||
98 | }; | ||
99 | |||
100 | #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr) | ||
101 | #define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj) | ||
102 | |||
103 | /* | ||
104 | * Prototype for sysfs creation function | ||
105 | */ | ||
106 | static int | ||
107 | efivar_create_sysfs_entry(struct efivar_entry *new_var); | ||
108 | |||
109 | static ssize_t | ||
110 | efivar_guid_read(struct efivar_entry *entry, char *buf) | ||
111 | { | ||
112 | struct efi_variable *var = &entry->var; | ||
113 | char *str = buf; | ||
114 | |||
115 | if (!entry || !buf) | ||
116 | return 0; | ||
117 | |||
118 | efi_guid_unparse(&var->VendorGuid, str); | ||
119 | str += strlen(str); | ||
120 | str += sprintf(str, "\n"); | ||
121 | |||
122 | return str - buf; | ||
123 | } | ||
124 | |||
125 | static ssize_t | ||
126 | efivar_attr_read(struct efivar_entry *entry, char *buf) | ||
127 | { | ||
128 | struct efi_variable *var = &entry->var; | ||
129 | char *str = buf; | ||
130 | |||
131 | if (!entry || !buf) | ||
132 | return -EINVAL; | ||
133 | |||
134 | var->DataSize = 1024; | ||
135 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
136 | return -EIO; | ||
137 | |||
138 | if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) | ||
139 | str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n"); | ||
140 | if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) | ||
141 | str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n"); | ||
142 | if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) | ||
143 | str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n"); | ||
144 | if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) | ||
145 | str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n"); | ||
146 | if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) | ||
147 | str += sprintf(str, | ||
148 | "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n"); | ||
149 | if (var->Attributes & | ||
150 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) | ||
151 | str += sprintf(str, | ||
152 | "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n"); | ||
153 | if (var->Attributes & EFI_VARIABLE_APPEND_WRITE) | ||
154 | str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n"); | ||
155 | return str - buf; | ||
156 | } | ||
157 | |||
158 | static ssize_t | ||
159 | efivar_size_read(struct efivar_entry *entry, char *buf) | ||
160 | { | ||
161 | struct efi_variable *var = &entry->var; | ||
162 | char *str = buf; | ||
163 | |||
164 | if (!entry || !buf) | ||
165 | return -EINVAL; | ||
166 | |||
167 | var->DataSize = 1024; | ||
168 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
169 | return -EIO; | ||
170 | |||
171 | str += sprintf(str, "0x%lx\n", var->DataSize); | ||
172 | return str - buf; | ||
173 | } | ||
174 | |||
175 | static ssize_t | ||
176 | efivar_data_read(struct efivar_entry *entry, char *buf) | ||
177 | { | ||
178 | struct efi_variable *var = &entry->var; | ||
179 | |||
180 | if (!entry || !buf) | ||
181 | return -EINVAL; | ||
182 | |||
183 | var->DataSize = 1024; | ||
184 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
185 | return -EIO; | ||
186 | |||
187 | memcpy(buf, var->Data, var->DataSize); | ||
188 | return var->DataSize; | ||
189 | } | ||
190 | /* | ||
191 | * We allow each variable to be edited via rewriting the | ||
192 | * entire efi variable structure. | ||
193 | */ | ||
194 | static ssize_t | ||
195 | efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | ||
196 | { | ||
197 | struct efi_variable *new_var, *var = &entry->var; | ||
198 | int err; | ||
199 | |||
200 | if (count != sizeof(struct efi_variable)) | ||
201 | return -EINVAL; | ||
202 | |||
203 | new_var = (struct efi_variable *)buf; | ||
204 | /* | ||
205 | * If only updating the variable data, then the name | ||
206 | * and guid should remain the same | ||
207 | */ | ||
208 | if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || | ||
209 | efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { | ||
210 | printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | |||
214 | if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ | ||
215 | printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
220 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { | ||
221 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | memcpy(&entry->var, new_var, count); | ||
226 | |||
227 | err = efivar_entry_set(entry, new_var->Attributes, | ||
228 | new_var->DataSize, new_var->Data, false); | ||
229 | if (err) { | ||
230 | printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); | ||
231 | return -EIO; | ||
232 | } | ||
233 | |||
234 | return count; | ||
235 | } | ||
236 | |||
237 | static ssize_t | ||
238 | efivar_show_raw(struct efivar_entry *entry, char *buf) | ||
239 | { | ||
240 | struct efi_variable *var = &entry->var; | ||
241 | |||
242 | if (!entry || !buf) | ||
243 | return 0; | ||
244 | |||
245 | var->DataSize = 1024; | ||
246 | if (efivar_entry_get(entry, &entry->var.Attributes, | ||
247 | &entry->var.DataSize, entry->var.Data)) | ||
248 | return -EIO; | ||
249 | |||
250 | memcpy(buf, var, sizeof(*var)); | ||
251 | |||
252 | return sizeof(*var); | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * Generic read/write functions that call the specific functions of | ||
257 | * the attributes... | ||
258 | */ | ||
259 | static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr, | ||
260 | char *buf) | ||
261 | { | ||
262 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
263 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
264 | ssize_t ret = -EIO; | ||
265 | |||
266 | if (!capable(CAP_SYS_ADMIN)) | ||
267 | return -EACCES; | ||
268 | |||
269 | if (efivar_attr->show) { | ||
270 | ret = efivar_attr->show(var, buf); | ||
271 | } | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, | ||
276 | const char *buf, size_t count) | ||
277 | { | ||
278 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
279 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
280 | ssize_t ret = -EIO; | ||
281 | |||
282 | if (!capable(CAP_SYS_ADMIN)) | ||
283 | return -EACCES; | ||
284 | |||
285 | if (efivar_attr->store) | ||
286 | ret = efivar_attr->store(var, buf, count); | ||
287 | |||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | static const struct sysfs_ops efivar_attr_ops = { | ||
292 | .show = efivar_attr_show, | ||
293 | .store = efivar_attr_store, | ||
294 | }; | ||
295 | |||
296 | static void efivar_release(struct kobject *kobj) | ||
297 | { | ||
298 | struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj); | ||
299 | kfree(var); | ||
300 | } | ||
301 | |||
302 | static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL); | ||
303 | static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL); | ||
304 | static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL); | ||
305 | static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL); | ||
306 | static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw); | ||
307 | |||
308 | static struct attribute *def_attrs[] = { | ||
309 | &efivar_attr_guid.attr, | ||
310 | &efivar_attr_size.attr, | ||
311 | &efivar_attr_attributes.attr, | ||
312 | &efivar_attr_data.attr, | ||
313 | &efivar_attr_raw_var.attr, | ||
314 | NULL, | ||
315 | }; | ||
316 | |||
317 | static struct kobj_type efivar_ktype = { | ||
318 | .release = efivar_release, | ||
319 | .sysfs_ops = &efivar_attr_ops, | ||
320 | .default_attrs = def_attrs, | ||
321 | }; | ||
322 | |||
323 | static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | ||
324 | struct bin_attribute *bin_attr, | ||
325 | char *buf, loff_t pos, size_t count) | ||
326 | { | ||
327 | struct efi_variable *new_var = (struct efi_variable *)buf; | ||
328 | struct efivar_entry *new_entry; | ||
329 | int err; | ||
330 | |||
331 | if (!capable(CAP_SYS_ADMIN)) | ||
332 | return -EACCES; | ||
333 | |||
334 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
335 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { | ||
336 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); | ||
341 | if (!new_entry) | ||
342 | return -ENOMEM; | ||
343 | |||
344 | memcpy(&new_entry->var, new_var, sizeof(*new_var)); | ||
345 | |||
346 | err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, | ||
347 | new_var->Data, &efivar_sysfs_list); | ||
348 | if (err) { | ||
349 | if (err == -EEXIST) | ||
350 | err = -EINVAL; | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | if (efivar_create_sysfs_entry(new_entry)) { | ||
355 | printk(KERN_WARNING "efivars: failed to create sysfs entry.\n"); | ||
356 | kfree(new_entry); | ||
357 | } | ||
358 | return count; | ||
359 | |||
360 | out: | ||
361 | kfree(new_entry); | ||
362 | return err; | ||
363 | } | ||
364 | |||
365 | static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | ||
366 | struct bin_attribute *bin_attr, | ||
367 | char *buf, loff_t pos, size_t count) | ||
368 | { | ||
369 | struct efi_variable *del_var = (struct efi_variable *)buf; | ||
370 | struct efivar_entry *entry; | ||
371 | int err = 0; | ||
372 | |||
373 | if (!capable(CAP_SYS_ADMIN)) | ||
374 | return -EACCES; | ||
375 | |||
376 | efivar_entry_iter_begin(); | ||
377 | entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, | ||
378 | &efivar_sysfs_list, true); | ||
379 | if (!entry) | ||
380 | err = -EINVAL; | ||
381 | else if (__efivar_entry_delete(entry)) | ||
382 | err = -EIO; | ||
383 | |||
384 | efivar_entry_iter_end(); | ||
385 | |||
386 | if (err) | ||
387 | return err; | ||
388 | |||
389 | efivar_unregister(entry); | ||
390 | |||
391 | /* It's dead Jim.... */ | ||
392 | return count; | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * efivar_create_sysfs_entry - create a new entry in sysfs | ||
397 | * @new_var: efivar entry to create | ||
398 | * | ||
399 | * Returns 1 on failure, 0 on success | ||
400 | */ | ||
401 | static int | ||
402 | efivar_create_sysfs_entry(struct efivar_entry *new_var) | ||
403 | { | ||
404 | int i, short_name_size; | ||
405 | char *short_name; | ||
406 | unsigned long variable_name_size; | ||
407 | efi_char16_t *variable_name; | ||
408 | |||
409 | variable_name = new_var->var.VariableName; | ||
410 | variable_name_size = utf16_strlen(variable_name) * sizeof(efi_char16_t); | ||
411 | |||
412 | /* | ||
413 | * Length of the variable bytes in ASCII, plus the '-' separator, | ||
414 | * plus the GUID, plus trailing NUL | ||
415 | */ | ||
416 | short_name_size = variable_name_size / sizeof(efi_char16_t) | ||
417 | + 1 + EFI_VARIABLE_GUID_LEN + 1; | ||
418 | |||
419 | short_name = kzalloc(short_name_size, GFP_KERNEL); | ||
420 | |||
421 | if (!short_name) { | ||
422 | kfree(short_name); | ||
423 | return 1; | ||
424 | } | ||
425 | |||
426 | /* Convert Unicode to normal chars (assume top bits are 0), | ||
427 | ala UTF-8 */ | ||
428 | for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { | ||
429 | short_name[i] = variable_name[i] & 0xFF; | ||
430 | } | ||
431 | /* This is ugly, but necessary to separate one vendor's | ||
432 | private variables from another's. */ | ||
433 | |||
434 | *(short_name + strlen(short_name)) = '-'; | ||
435 | efi_guid_unparse(&new_var->var.VendorGuid, | ||
436 | short_name + strlen(short_name)); | ||
437 | |||
438 | new_var->kobj.kset = efivars_kset; | ||
439 | |||
440 | i = kobject_init_and_add(&new_var->kobj, &efivar_ktype, | ||
441 | NULL, "%s", short_name); | ||
442 | kfree(short_name); | ||
443 | if (i) | ||
444 | return 1; | ||
445 | |||
446 | kobject_uevent(&new_var->kobj, KOBJ_ADD); | ||
447 | efivar_entry_add(new_var, &efivar_sysfs_list); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int | ||
453 | create_efivars_bin_attributes(void) | ||
454 | { | ||
455 | struct bin_attribute *attr; | ||
456 | int error; | ||
457 | |||
458 | /* new_var */ | ||
459 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
460 | if (!attr) | ||
461 | return -ENOMEM; | ||
462 | |||
463 | attr->attr.name = "new_var"; | ||
464 | attr->attr.mode = 0200; | ||
465 | attr->write = efivar_create; | ||
466 | efivars_new_var = attr; | ||
467 | |||
468 | /* del_var */ | ||
469 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
470 | if (!attr) { | ||
471 | error = -ENOMEM; | ||
472 | goto out_free; | ||
473 | } | ||
474 | attr->attr.name = "del_var"; | ||
475 | attr->attr.mode = 0200; | ||
476 | attr->write = efivar_delete; | ||
477 | efivars_del_var = attr; | ||
478 | |||
479 | sysfs_bin_attr_init(efivars_new_var); | ||
480 | sysfs_bin_attr_init(efivars_del_var); | ||
481 | |||
482 | /* Register */ | ||
483 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
484 | if (error) { | ||
485 | printk(KERN_ERR "efivars: unable to create new_var sysfs file" | ||
486 | " due to error %d\n", error); | ||
487 | goto out_free; | ||
488 | } | ||
489 | |||
490 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var); | ||
491 | if (error) { | ||
492 | printk(KERN_ERR "efivars: unable to create del_var sysfs file" | ||
493 | " due to error %d\n", error); | ||
494 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
495 | goto out_free; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | out_free: | ||
500 | kfree(efivars_del_var); | ||
501 | efivars_del_var = NULL; | ||
502 | kfree(efivars_new_var); | ||
503 | efivars_new_var = NULL; | ||
504 | return error; | ||
505 | } | ||
506 | |||
507 | static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor, | ||
508 | unsigned long name_size, void *data) | ||
509 | { | ||
510 | struct efivar_entry *entry = data; | ||
511 | |||
512 | if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false)) | ||
513 | return 0; | ||
514 | |||
515 | memcpy(entry->var.VariableName, name, name_size); | ||
516 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
517 | |||
518 | return 1; | ||
519 | } | ||
520 | |||
521 | static void efivar_update_sysfs_entries(struct work_struct *work) | ||
522 | { | ||
523 | struct efivar_entry *entry; | ||
524 | int err; | ||
525 | |||
526 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
527 | if (!entry) | ||
528 | return; | ||
529 | |||
530 | /* Add new sysfs entries */ | ||
531 | while (1) { | ||
532 | memset(entry, 0, sizeof(*entry)); | ||
533 | |||
534 | err = efivar_init(efivar_update_sysfs_entry, entry, | ||
535 | true, false, &efivar_sysfs_list); | ||
536 | if (!err) | ||
537 | break; | ||
538 | |||
539 | efivar_create_sysfs_entry(entry); | ||
540 | } | ||
541 | |||
542 | kfree(entry); | ||
543 | } | ||
544 | |||
545 | static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor, | ||
546 | unsigned long name_size, void *data) | ||
547 | { | ||
548 | struct efivar_entry *entry; | ||
549 | |||
550 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
551 | if (!entry) | ||
552 | return -ENOMEM; | ||
553 | |||
554 | memcpy(entry->var.VariableName, name, name_size); | ||
555 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
556 | |||
557 | efivar_create_sysfs_entry(entry); | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) | ||
563 | { | ||
564 | efivar_entry_remove(entry); | ||
565 | efivar_unregister(entry); | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | void efivars_sysfs_exit(void) | ||
570 | { | ||
571 | /* Remove all entries and destroy */ | ||
572 | __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); | ||
573 | |||
574 | if (efivars_new_var) | ||
575 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
576 | if (efivars_del_var) | ||
577 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var); | ||
578 | kfree(efivars_new_var); | ||
579 | kfree(efivars_del_var); | ||
580 | kset_unregister(efivars_kset); | ||
581 | } | ||
582 | |||
583 | int efivars_sysfs_init(void) | ||
584 | { | ||
585 | struct kobject *parent_kobj = efivars_kobject(); | ||
586 | int error = 0; | ||
587 | |||
588 | /* No efivars has been registered yet */ | ||
589 | if (!parent_kobj) | ||
590 | return 0; | ||
591 | |||
592 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, | ||
593 | EFIVARS_DATE); | ||
594 | |||
595 | efivars_kset = kset_create_and_add("vars", NULL, parent_kobj); | ||
596 | if (!efivars_kset) { | ||
597 | printk(KERN_ERR "efivars: Subsystem registration failed.\n"); | ||
598 | return -ENOMEM; | ||
599 | } | ||
600 | |||
601 | efivar_init(efivars_sysfs_callback, NULL, false, | ||
602 | true, &efivar_sysfs_list); | ||
603 | |||
604 | error = create_efivars_bin_attributes(); | ||
605 | if (error) { | ||
606 | efivars_sysfs_exit(); | ||
607 | return error; | ||
608 | } | ||
609 | |||
610 | INIT_WORK(&efivar_work, efivar_update_sysfs_entries); | ||
611 | |||
612 | return 0; | ||
613 | } | ||
614 | EXPORT_SYMBOL_GPL(efivars_sysfs_init); | ||
615 | |||
616 | module_init(efivars_sysfs_init); | ||
617 | module_exit(efivars_sysfs_exit); | ||
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efi/vars.c index af396758482f..dd1c20a426fa 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efi/vars.c | |||
@@ -1,12 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * EFI Variables - efivars.c | 2 | * Originally from efivars.c |
3 | * | 3 | * |
4 | * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> | 4 | * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com> |
5 | * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> | 5 | * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com> |
6 | * | 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 | 7 | * 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 | 8 | * 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 | 9 | * the Free Software Foundation; either version 2 of the License, or |
@@ -20,49 +17,6 @@ | |||
20 | * You should have received a copy of the GNU General Public License | 17 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * 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 | */ | 20 | */ |
67 | 21 | ||
68 | #include <linux/capability.h> | 22 | #include <linux/capability.h> |
@@ -75,65 +29,16 @@ | |||
75 | #include <linux/smp.h> | 29 | #include <linux/smp.h> |
76 | #include <linux/efi.h> | 30 | #include <linux/efi.h> |
77 | #include <linux/sysfs.h> | 31 | #include <linux/sysfs.h> |
78 | #include <linux/kobject.h> | ||
79 | #include <linux/device.h> | 32 | #include <linux/device.h> |
80 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
81 | #include <linux/ctype.h> | 34 | #include <linux/ctype.h> |
82 | 35 | ||
83 | #include <linux/fs.h> | ||
84 | #include <linux/ramfs.h> | ||
85 | #include <linux/pagemap.h> | ||
86 | |||
87 | #include <asm/uaccess.h> | ||
88 | |||
89 | #define EFIVARS_VERSION "0.08" | ||
90 | #define EFIVARS_DATE "2004-May-17" | ||
91 | |||
92 | MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); | ||
93 | MODULE_DESCRIPTION("sysfs interface to EFI Variables"); | ||
94 | MODULE_LICENSE("GPL"); | ||
95 | MODULE_VERSION(EFIVARS_VERSION); | ||
96 | |||
97 | LIST_HEAD(efivar_sysfs_list); | ||
98 | EXPORT_SYMBOL_GPL(efivar_sysfs_list); | ||
99 | |||
100 | struct efivar_attribute { | ||
101 | struct attribute attr; | ||
102 | ssize_t (*show) (struct efivar_entry *entry, char *buf); | ||
103 | ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); | ||
104 | }; | ||
105 | |||
106 | /* Private pointer to registered efivars */ | 36 | /* Private pointer to registered efivars */ |
107 | static struct efivars *__efivars; | 37 | static struct efivars *__efivars; |
108 | 38 | ||
109 | static struct kset *efivars_kset; | ||
110 | |||
111 | static struct bin_attribute *efivars_new_var; | ||
112 | static struct bin_attribute *efivars_del_var; | ||
113 | |||
114 | #define EFIVAR_ATTR(_name, _mode, _show, _store) \ | ||
115 | struct efivar_attribute efivar_attr_##_name = { \ | ||
116 | .attr = {.name = __stringify(_name), .mode = _mode}, \ | ||
117 | .show = _show, \ | ||
118 | .store = _store, \ | ||
119 | }; | ||
120 | |||
121 | #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr) | ||
122 | #define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj) | ||
123 | |||
124 | /* | ||
125 | * Prototype for sysfs creation function | ||
126 | */ | ||
127 | static int | ||
128 | efivar_create_sysfs_entry(struct efivar_entry *new_var); | ||
129 | |||
130 | /* | ||
131 | * Prototype for workqueue functions updating sysfs entry | ||
132 | */ | ||
133 | |||
134 | static void efivar_update_sysfs_entries(struct work_struct *); | ||
135 | static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); | ||
136 | static bool efivar_wq_enabled = true; | 39 | static bool efivar_wq_enabled = true; |
40 | DECLARE_WORK(efivar_work, NULL); | ||
41 | EXPORT_SYMBOL_GPL(efivar_work); | ||
137 | 42 | ||
138 | static bool | 43 | static bool |
139 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, | 44 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, |
@@ -343,220 +248,6 @@ check_var_size(u32 attributes, unsigned long size) | |||
343 | return status; | 248 | return status; |
344 | } | 249 | } |
345 | 250 | ||
346 | static ssize_t | ||
347 | efivar_guid_read(struct efivar_entry *entry, char *buf) | ||
348 | { | ||
349 | struct efi_variable *var = &entry->var; | ||
350 | char *str = buf; | ||
351 | |||
352 | if (!entry || !buf) | ||
353 | return 0; | ||
354 | |||
355 | efi_guid_unparse(&var->VendorGuid, str); | ||
356 | str += strlen(str); | ||
357 | str += sprintf(str, "\n"); | ||
358 | |||
359 | return str - buf; | ||
360 | } | ||
361 | |||
362 | static ssize_t | ||
363 | efivar_attr_read(struct efivar_entry *entry, char *buf) | ||
364 | { | ||
365 | struct efi_variable *var = &entry->var; | ||
366 | char *str = buf; | ||
367 | |||
368 | if (!entry || !buf) | ||
369 | return -EINVAL; | ||
370 | |||
371 | var->DataSize = 1024; | ||
372 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
373 | return -EIO; | ||
374 | |||
375 | if (var->Attributes & EFI_VARIABLE_NON_VOLATILE) | ||
376 | str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n"); | ||
377 | if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS) | ||
378 | str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n"); | ||
379 | if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) | ||
380 | str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n"); | ||
381 | if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) | ||
382 | str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n"); | ||
383 | if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) | ||
384 | str += sprintf(str, | ||
385 | "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n"); | ||
386 | if (var->Attributes & | ||
387 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) | ||
388 | str += sprintf(str, | ||
389 | "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n"); | ||
390 | if (var->Attributes & EFI_VARIABLE_APPEND_WRITE) | ||
391 | str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n"); | ||
392 | return str - buf; | ||
393 | } | ||
394 | |||
395 | static ssize_t | ||
396 | efivar_size_read(struct efivar_entry *entry, char *buf) | ||
397 | { | ||
398 | struct efi_variable *var = &entry->var; | ||
399 | char *str = buf; | ||
400 | |||
401 | if (!entry || !buf) | ||
402 | return -EINVAL; | ||
403 | |||
404 | var->DataSize = 1024; | ||
405 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
406 | return -EIO; | ||
407 | |||
408 | str += sprintf(str, "0x%lx\n", var->DataSize); | ||
409 | return str - buf; | ||
410 | } | ||
411 | |||
412 | static ssize_t | ||
413 | efivar_data_read(struct efivar_entry *entry, char *buf) | ||
414 | { | ||
415 | struct efi_variable *var = &entry->var; | ||
416 | |||
417 | if (!entry || !buf) | ||
418 | return -EINVAL; | ||
419 | |||
420 | var->DataSize = 1024; | ||
421 | if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data)) | ||
422 | return -EIO; | ||
423 | |||
424 | memcpy(buf, var->Data, var->DataSize); | ||
425 | return var->DataSize; | ||
426 | } | ||
427 | /* | ||
428 | * We allow each variable to be edited via rewriting the | ||
429 | * entire efi variable structure. | ||
430 | */ | ||
431 | static ssize_t | ||
432 | efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | ||
433 | { | ||
434 | struct efi_variable *new_var, *var = &entry->var; | ||
435 | int err; | ||
436 | |||
437 | if (count != sizeof(struct efi_variable)) | ||
438 | return -EINVAL; | ||
439 | |||
440 | new_var = (struct efi_variable *)buf; | ||
441 | /* | ||
442 | * If only updating the variable data, then the name | ||
443 | * and guid should remain the same | ||
444 | */ | ||
445 | if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) || | ||
446 | efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) { | ||
447 | printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n"); | ||
448 | return -EINVAL; | ||
449 | } | ||
450 | |||
451 | if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){ | ||
452 | printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n"); | ||
453 | return -EINVAL; | ||
454 | } | ||
455 | |||
456 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
457 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { | ||
458 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | |||
462 | memcpy(&entry->var, new_var, count); | ||
463 | |||
464 | err = efivar_entry_set(entry, new_var->Attributes, | ||
465 | new_var->DataSize, new_var->Data, false); | ||
466 | if (err) { | ||
467 | printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err); | ||
468 | return -EIO; | ||
469 | } | ||
470 | |||
471 | return count; | ||
472 | } | ||
473 | |||
474 | static ssize_t | ||
475 | efivar_show_raw(struct efivar_entry *entry, char *buf) | ||
476 | { | ||
477 | struct efi_variable *var = &entry->var; | ||
478 | |||
479 | if (!entry || !buf) | ||
480 | return 0; | ||
481 | |||
482 | var->DataSize = 1024; | ||
483 | if (efivar_entry_get(entry, &entry->var.Attributes, | ||
484 | &entry->var.DataSize, entry->var.Data)) | ||
485 | return -EIO; | ||
486 | |||
487 | memcpy(buf, var, sizeof(*var)); | ||
488 | |||
489 | return sizeof(*var); | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * Generic read/write functions that call the specific functions of | ||
494 | * the attributes... | ||
495 | */ | ||
496 | static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr, | ||
497 | char *buf) | ||
498 | { | ||
499 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
500 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
501 | ssize_t ret = -EIO; | ||
502 | |||
503 | if (!capable(CAP_SYS_ADMIN)) | ||
504 | return -EACCES; | ||
505 | |||
506 | if (efivar_attr->show) { | ||
507 | ret = efivar_attr->show(var, buf); | ||
508 | } | ||
509 | return ret; | ||
510 | } | ||
511 | |||
512 | static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr, | ||
513 | const char *buf, size_t count) | ||
514 | { | ||
515 | struct efivar_entry *var = to_efivar_entry(kobj); | ||
516 | struct efivar_attribute *efivar_attr = to_efivar_attr(attr); | ||
517 | ssize_t ret = -EIO; | ||
518 | |||
519 | if (!capable(CAP_SYS_ADMIN)) | ||
520 | return -EACCES; | ||
521 | |||
522 | if (efivar_attr->store) | ||
523 | ret = efivar_attr->store(var, buf, count); | ||
524 | |||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static const struct sysfs_ops efivar_attr_ops = { | ||
529 | .show = efivar_attr_show, | ||
530 | .store = efivar_attr_store, | ||
531 | }; | ||
532 | |||
533 | static void efivar_release(struct kobject *kobj) | ||
534 | { | ||
535 | struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj); | ||
536 | kfree(var); | ||
537 | } | ||
538 | |||
539 | static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL); | ||
540 | static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL); | ||
541 | static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL); | ||
542 | static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL); | ||
543 | static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw); | ||
544 | |||
545 | static struct attribute *def_attrs[] = { | ||
546 | &efivar_attr_guid.attr, | ||
547 | &efivar_attr_size.attr, | ||
548 | &efivar_attr_attributes.attr, | ||
549 | &efivar_attr_data.attr, | ||
550 | &efivar_attr_raw_var.attr, | ||
551 | NULL, | ||
552 | }; | ||
553 | |||
554 | static struct kobj_type efivar_ktype = { | ||
555 | .release = efivar_release, | ||
556 | .sysfs_ops = &efivar_attr_ops, | ||
557 | .default_attrs = def_attrs, | ||
558 | }; | ||
559 | |||
560 | static int efi_status_to_err(efi_status_t status) | 251 | static int efi_status_to_err(efi_status_t status) |
561 | { | 252 | { |
562 | int err; | 253 | int err; |
@@ -590,78 +281,6 @@ static int efi_status_to_err(efi_status_t status) | |||
590 | return err; | 281 | return err; |
591 | } | 282 | } |
592 | 283 | ||
593 | static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | ||
594 | struct bin_attribute *bin_attr, | ||
595 | char *buf, loff_t pos, size_t count) | ||
596 | { | ||
597 | struct efi_variable *new_var = (struct efi_variable *)buf; | ||
598 | struct efivar_entry *new_entry; | ||
599 | int err; | ||
600 | |||
601 | if (!capable(CAP_SYS_ADMIN)) | ||
602 | return -EACCES; | ||
603 | |||
604 | if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || | ||
605 | efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) { | ||
606 | printk(KERN_ERR "efivars: Malformed variable content\n"); | ||
607 | return -EINVAL; | ||
608 | } | ||
609 | |||
610 | new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); | ||
611 | if (!new_entry) | ||
612 | return -ENOMEM; | ||
613 | |||
614 | memcpy(&new_entry->var, new_var, sizeof(*new_var)); | ||
615 | |||
616 | err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize, | ||
617 | new_var->Data, &efivar_sysfs_list); | ||
618 | if (err) { | ||
619 | if (err == -EEXIST) | ||
620 | err = -EINVAL; | ||
621 | goto out; | ||
622 | } | ||
623 | |||
624 | if (efivar_create_sysfs_entry(new_entry)) { | ||
625 | printk(KERN_WARNING "efivars: failed to create sysfs entry.\n"); | ||
626 | kfree(new_entry); | ||
627 | } | ||
628 | return count; | ||
629 | |||
630 | out: | ||
631 | kfree(new_entry); | ||
632 | return err; | ||
633 | } | ||
634 | |||
635 | static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | ||
636 | struct bin_attribute *bin_attr, | ||
637 | char *buf, loff_t pos, size_t count) | ||
638 | { | ||
639 | struct efi_variable *del_var = (struct efi_variable *)buf; | ||
640 | struct efivar_entry *entry; | ||
641 | int err = 0; | ||
642 | |||
643 | if (!capable(CAP_SYS_ADMIN)) | ||
644 | return -EACCES; | ||
645 | |||
646 | efivar_entry_iter_begin(); | ||
647 | entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid, | ||
648 | &efivar_sysfs_list, true); | ||
649 | if (!entry) | ||
650 | err = -EINVAL; | ||
651 | else if (__efivar_entry_delete(entry)) | ||
652 | err = -EIO; | ||
653 | |||
654 | efivar_entry_iter_end(); | ||
655 | |||
656 | if (err) | ||
657 | return err; | ||
658 | |||
659 | efivar_unregister(entry); | ||
660 | |||
661 | /* It's dead Jim.... */ | ||
662 | return count; | ||
663 | } | ||
664 | |||
665 | static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor, | 284 | static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor, |
666 | struct list_head *head) | 285 | struct list_head *head) |
667 | { | 286 | { |
@@ -684,20 +303,6 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor, | |||
684 | return found; | 303 | return found; |
685 | } | 304 | } |
686 | 305 | ||
687 | static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor, | ||
688 | unsigned long name_size, void *data) | ||
689 | { | ||
690 | struct efivar_entry *entry = data; | ||
691 | |||
692 | if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false)) | ||
693 | return 0; | ||
694 | |||
695 | memcpy(entry->var.VariableName, name, name_size); | ||
696 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
697 | |||
698 | return 1; | ||
699 | } | ||
700 | |||
701 | /* | 306 | /* |
702 | * Returns the size of variable_name, in bytes, including the | 307 | * Returns the size of variable_name, in bytes, including the |
703 | * terminating NULL character, or variable_name_size if no NULL | 308 | * terminating NULL character, or variable_name_size if no NULL |
@@ -723,210 +328,6 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name, | |||
723 | return min(len, variable_name_size); | 328 | return min(len, variable_name_size); |
724 | } | 329 | } |
725 | 330 | ||
726 | static void efivar_update_sysfs_entries(struct work_struct *work) | ||
727 | { | ||
728 | struct efivar_entry *entry; | ||
729 | int err; | ||
730 | |||
731 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
732 | if (!entry) | ||
733 | return; | ||
734 | |||
735 | /* Add new sysfs entries */ | ||
736 | while (1) { | ||
737 | memset(entry, 0, sizeof(*entry)); | ||
738 | |||
739 | err = efivar_init(efivar_update_sysfs_entry, entry, | ||
740 | true, false, &efivar_sysfs_list); | ||
741 | if (!err) | ||
742 | break; | ||
743 | |||
744 | efivar_create_sysfs_entry(entry); | ||
745 | } | ||
746 | |||
747 | kfree(entry); | ||
748 | } | ||
749 | |||
750 | /* | ||
751 | * Let's not leave out systab information that snuck into | ||
752 | * the efivars driver | ||
753 | */ | ||
754 | static ssize_t systab_show(struct kobject *kobj, | ||
755 | struct kobj_attribute *attr, char *buf) | ||
756 | { | ||
757 | char *str = buf; | ||
758 | |||
759 | if (!kobj || !buf) | ||
760 | return -EINVAL; | ||
761 | |||
762 | if (efi.mps != EFI_INVALID_TABLE_ADDR) | ||
763 | str += sprintf(str, "MPS=0x%lx\n", efi.mps); | ||
764 | if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) | ||
765 | str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20); | ||
766 | if (efi.acpi != EFI_INVALID_TABLE_ADDR) | ||
767 | str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); | ||
768 | if (efi.smbios != EFI_INVALID_TABLE_ADDR) | ||
769 | str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); | ||
770 | if (efi.hcdp != EFI_INVALID_TABLE_ADDR) | ||
771 | str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); | ||
772 | if (efi.boot_info != EFI_INVALID_TABLE_ADDR) | ||
773 | str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info); | ||
774 | if (efi.uga != EFI_INVALID_TABLE_ADDR) | ||
775 | str += sprintf(str, "UGA=0x%lx\n", efi.uga); | ||
776 | |||
777 | return str - buf; | ||
778 | } | ||
779 | |||
780 | static struct kobj_attribute efi_attr_systab = | ||
781 | __ATTR(systab, 0400, systab_show, NULL); | ||
782 | |||
783 | static struct attribute *efi_subsys_attrs[] = { | ||
784 | &efi_attr_systab.attr, | ||
785 | NULL, /* maybe more in the future? */ | ||
786 | }; | ||
787 | |||
788 | static struct attribute_group efi_subsys_attr_group = { | ||
789 | .attrs = efi_subsys_attrs, | ||
790 | }; | ||
791 | |||
792 | static struct kobject *efi_kobj; | ||
793 | |||
794 | /** | ||
795 | * efivar_create_sysfs_entry - create a new entry in sysfs | ||
796 | * @new_var: efivar entry to create | ||
797 | * | ||
798 | * Returns 1 on failure, 0 on success | ||
799 | */ | ||
800 | static int | ||
801 | efivar_create_sysfs_entry(struct efivar_entry *new_var) | ||
802 | { | ||
803 | int i, short_name_size; | ||
804 | char *short_name; | ||
805 | unsigned long variable_name_size; | ||
806 | efi_char16_t *variable_name; | ||
807 | |||
808 | variable_name = new_var->var.VariableName; | ||
809 | variable_name_size = utf16_strlen(variable_name) * sizeof(efi_char16_t); | ||
810 | |||
811 | /* | ||
812 | * Length of the variable bytes in ASCII, plus the '-' separator, | ||
813 | * plus the GUID, plus trailing NUL | ||
814 | */ | ||
815 | short_name_size = variable_name_size / sizeof(efi_char16_t) | ||
816 | + 1 + EFI_VARIABLE_GUID_LEN + 1; | ||
817 | |||
818 | short_name = kzalloc(short_name_size, GFP_KERNEL); | ||
819 | |||
820 | if (!short_name) { | ||
821 | kfree(short_name); | ||
822 | return 1; | ||
823 | } | ||
824 | |||
825 | /* Convert Unicode to normal chars (assume top bits are 0), | ||
826 | ala UTF-8 */ | ||
827 | for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { | ||
828 | short_name[i] = variable_name[i] & 0xFF; | ||
829 | } | ||
830 | /* This is ugly, but necessary to separate one vendor's | ||
831 | private variables from another's. */ | ||
832 | |||
833 | *(short_name + strlen(short_name)) = '-'; | ||
834 | efi_guid_unparse(&new_var->var.VendorGuid, | ||
835 | short_name + strlen(short_name)); | ||
836 | |||
837 | new_var->kobj.kset = efivars_kset; | ||
838 | |||
839 | i = kobject_init_and_add(&new_var->kobj, &efivar_ktype, | ||
840 | NULL, "%s", short_name); | ||
841 | kfree(short_name); | ||
842 | if (i) | ||
843 | return 1; | ||
844 | |||
845 | kobject_uevent(&new_var->kobj, KOBJ_ADD); | ||
846 | efivar_entry_add(new_var, &efivar_sysfs_list); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static int | ||
852 | create_efivars_bin_attributes(void) | ||
853 | { | ||
854 | struct bin_attribute *attr; | ||
855 | int error; | ||
856 | |||
857 | /* new_var */ | ||
858 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
859 | if (!attr) | ||
860 | return -ENOMEM; | ||
861 | |||
862 | attr->attr.name = "new_var"; | ||
863 | attr->attr.mode = 0200; | ||
864 | attr->write = efivar_create; | ||
865 | efivars_new_var = attr; | ||
866 | |||
867 | /* del_var */ | ||
868 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
869 | if (!attr) { | ||
870 | error = -ENOMEM; | ||
871 | goto out_free; | ||
872 | } | ||
873 | attr->attr.name = "del_var"; | ||
874 | attr->attr.mode = 0200; | ||
875 | attr->write = efivar_delete; | ||
876 | efivars_del_var = attr; | ||
877 | |||
878 | sysfs_bin_attr_init(efivars_new_var); | ||
879 | sysfs_bin_attr_init(efivars_del_var); | ||
880 | |||
881 | /* Register */ | ||
882 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
883 | if (error) { | ||
884 | printk(KERN_ERR "efivars: unable to create new_var sysfs file" | ||
885 | " due to error %d\n", error); | ||
886 | goto out_free; | ||
887 | } | ||
888 | |||
889 | error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var); | ||
890 | if (error) { | ||
891 | printk(KERN_ERR "efivars: unable to create del_var sysfs file" | ||
892 | " due to error %d\n", error); | ||
893 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
894 | goto out_free; | ||
895 | } | ||
896 | |||
897 | return 0; | ||
898 | out_free: | ||
899 | kfree(efivars_del_var); | ||
900 | efivars_del_var = NULL; | ||
901 | kfree(efivars_new_var); | ||
902 | efivars_new_var = NULL; | ||
903 | return error; | ||
904 | } | ||
905 | |||
906 | static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor, | ||
907 | unsigned long name_size, void *data) | ||
908 | { | ||
909 | struct efivar_entry *entry; | ||
910 | |||
911 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
912 | if (!entry) | ||
913 | return -ENOMEM; | ||
914 | |||
915 | memcpy(entry->var.VariableName, name, name_size); | ||
916 | memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); | ||
917 | |||
918 | efivar_create_sysfs_entry(entry); | ||
919 | |||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) | ||
924 | { | ||
925 | efivar_entry_remove(entry); | ||
926 | efivar_unregister(entry); | ||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | /* | 331 | /* |
931 | * Print a warning when duplicate EFI variables are encountered and | 332 | * Print a warning when duplicate EFI variables are encountered and |
932 | * disable the sysfs workqueue since the firmware is buggy. | 333 | * disable the sysfs workqueue since the firmware is buggy. |
@@ -956,59 +357,6 @@ static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | |||
956 | kfree(s8); | 357 | kfree(s8); |
957 | } | 358 | } |
958 | 359 | ||
959 | static struct kobject *efivars_kobj; | ||
960 | |||
961 | void efivars_sysfs_exit(void) | ||
962 | { | ||
963 | /* Remove all entries and destroy */ | ||
964 | __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); | ||
965 | |||
966 | if (efivars_new_var) | ||
967 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); | ||
968 | if (efivars_del_var) | ||
969 | sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var); | ||
970 | kfree(efivars_new_var); | ||
971 | kfree(efivars_del_var); | ||
972 | kobject_put(efivars_kobj); | ||
973 | kset_unregister(efivars_kset); | ||
974 | } | ||
975 | |||
976 | int efivars_sysfs_init(void) | ||
977 | { | ||
978 | struct kobject *parent_kobj = efivars_kobject(); | ||
979 | int error = 0; | ||
980 | |||
981 | /* No efivars has been registered yet */ | ||
982 | if (!parent_kobj) | ||
983 | return 0; | ||
984 | |||
985 | printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, | ||
986 | EFIVARS_DATE); | ||
987 | |||
988 | efivars_kset = kset_create_and_add("vars", NULL, parent_kobj); | ||
989 | if (!efivars_kset) { | ||
990 | printk(KERN_ERR "efivars: Subsystem registration failed.\n"); | ||
991 | return -ENOMEM; | ||
992 | } | ||
993 | |||
994 | efivars_kobj = kobject_create_and_add("efivars", parent_kobj); | ||
995 | if (!efivars_kobj) { | ||
996 | pr_err("efivars: Subsystem registration failed.\n"); | ||
997 | kset_unregister(efivars_kset); | ||
998 | return -ENOMEM; | ||
999 | } | ||
1000 | |||
1001 | efivar_init(efivars_sysfs_callback, NULL, false, | ||
1002 | true, &efivar_sysfs_list); | ||
1003 | |||
1004 | error = create_efivars_bin_attributes(); | ||
1005 | if (error) | ||
1006 | efivars_sysfs_exit(); | ||
1007 | |||
1008 | return error; | ||
1009 | } | ||
1010 | EXPORT_SYMBOL_GPL(efivars_sysfs_init); | ||
1011 | |||
1012 | /** | 360 | /** |
1013 | * efivar_init - build the initial list of EFI variables | 361 | * efivar_init - build the initial list of EFI variables |
1014 | * @func: callback function to invoke for every variable | 362 | * @func: callback function to invoke for every variable |
@@ -1154,17 +502,16 @@ static void efivar_entry_list_del_unlock(struct efivar_entry *entry) | |||
1154 | * __efivar_entry_delete - delete an EFI variable | 502 | * __efivar_entry_delete - delete an EFI variable |
1155 | * @entry: entry containing EFI variable to delete | 503 | * @entry: entry containing EFI variable to delete |
1156 | * | 504 | * |
1157 | * Delete the variable from the firmware and remove @entry from the | 505 | * Delete the variable from the firmware but leave @entry on the |
1158 | * variable list. It is the caller's responsibility to free @entry | 506 | * variable list. |
1159 | * once we return. | ||
1160 | * | 507 | * |
1161 | * This function differs from efivar_entry_delete() because it is | 508 | * This function differs from efivar_entry_delete() because it does |
1162 | * safe to be called from within a efivar_entry_iter_begin() and | 509 | * not remove @entry from the variable list. Also, it is safe to be |
510 | * called from within a efivar_entry_iter_begin() and | ||
1163 | * efivar_entry_iter_end() region, unlike efivar_entry_delete(). | 511 | * efivar_entry_iter_end() region, unlike efivar_entry_delete(). |
1164 | * | 512 | * |
1165 | * Returns 0 on success, or a converted EFI status code if | 513 | * Returns 0 on success, or a converted EFI status code if |
1166 | * set_variable() fails. If set_variable() fails the entry remains | 514 | * set_variable() fails. |
1167 | * on the list. | ||
1168 | */ | 515 | */ |
1169 | int __efivar_entry_delete(struct efivar_entry *entry) | 516 | int __efivar_entry_delete(struct efivar_entry *entry) |
1170 | { | 517 | { |
@@ -1176,12 +523,8 @@ int __efivar_entry_delete(struct efivar_entry *entry) | |||
1176 | status = ops->set_variable(entry->var.VariableName, | 523 | status = ops->set_variable(entry->var.VariableName, |
1177 | &entry->var.VendorGuid, | 524 | &entry->var.VendorGuid, |
1178 | 0, 0, NULL); | 525 | 0, 0, NULL); |
1179 | if (status) | ||
1180 | return efi_status_to_err(status); | ||
1181 | |||
1182 | list_del(&entry->list); | ||
1183 | 526 | ||
1184 | return 0; | 527 | return efi_status_to_err(status); |
1185 | } | 528 | } |
1186 | EXPORT_SYMBOL_GPL(__efivar_entry_delete); | 529 | EXPORT_SYMBOL_GPL(__efivar_entry_delete); |
1187 | 530 | ||
@@ -1259,6 +602,7 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | |||
1259 | spin_unlock_irq(&__efivars->lock); | 602 | spin_unlock_irq(&__efivars->lock); |
1260 | 603 | ||
1261 | return efi_status_to_err(status); | 604 | return efi_status_to_err(status); |
605 | |||
1262 | } | 606 | } |
1263 | EXPORT_SYMBOL_GPL(efivar_entry_set); | 607 | EXPORT_SYMBOL_GPL(efivar_entry_set); |
1264 | 608 | ||
@@ -1289,7 +633,7 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | |||
1289 | if (!ops->query_variable_info) | 633 | if (!ops->query_variable_info) |
1290 | return -ENOSYS; | 634 | return -ENOSYS; |
1291 | 635 | ||
1292 | if (!block && !spin_trylock_irqsave(&__efivars->lock, flags)) | 636 | if (!block && spin_trylock_irqsave(&__efivars->lock, flags)) |
1293 | return -EBUSY; | 637 | return -EBUSY; |
1294 | else | 638 | else |
1295 | spin_lock_irqsave(&__efivars->lock, flags); | 639 | spin_lock_irqsave(&__efivars->lock, flags); |
@@ -1703,92 +1047,3 @@ out: | |||
1703 | return rv; | 1047 | return rv; |
1704 | } | 1048 | } |
1705 | EXPORT_SYMBOL_GPL(efivars_unregister); | 1049 | EXPORT_SYMBOL_GPL(efivars_unregister); |
1706 | |||
1707 | static struct efivars generic_efivars; | ||
1708 | static struct efivar_operations generic_ops; | ||
1709 | |||
1710 | static int generic_ops_register(void) | ||
1711 | { | ||
1712 | int error; | ||
1713 | |||
1714 | generic_ops.get_variable = efi.get_variable; | ||
1715 | generic_ops.set_variable = efi.set_variable; | ||
1716 | generic_ops.get_next_variable = efi.get_next_variable; | ||
1717 | generic_ops.query_variable_info = efi.query_variable_info; | ||
1718 | |||
1719 | error = efivars_register(&generic_efivars, &generic_ops, efi_kobj); | ||
1720 | if (error) | ||
1721 | return error; | ||
1722 | |||
1723 | error = efivars_sysfs_init(); | ||
1724 | if (error) | ||
1725 | efivars_unregister(&generic_efivars); | ||
1726 | |||
1727 | return error; | ||
1728 | } | ||
1729 | |||
1730 | static void generic_ops_unregister(void) | ||
1731 | { | ||
1732 | efivars_sysfs_exit(); | ||
1733 | efivars_unregister(&generic_efivars); | ||
1734 | } | ||
1735 | |||
1736 | /* | ||
1737 | * For now we register the efi subsystem with the firmware subsystem | ||
1738 | * and the vars subsystem with the efi subsystem. In the future, it | ||
1739 | * might make sense to split off the efi subsystem into its own | ||
1740 | * driver, but for now only efivars will register with it, so just | ||
1741 | * include it here. | ||
1742 | */ | ||
1743 | |||
1744 | static int __init | ||
1745 | efivars_init(void) | ||
1746 | { | ||
1747 | int error; | ||
1748 | |||
1749 | if (!efi_enabled(EFI_RUNTIME_SERVICES)) | ||
1750 | return 0; | ||
1751 | |||
1752 | /* Register the efi directory at /sys/firmware/efi */ | ||
1753 | efi_kobj = kobject_create_and_add("efi", firmware_kobj); | ||
1754 | if (!efi_kobj) { | ||
1755 | printk(KERN_ERR "efivars: Firmware registration failed.\n"); | ||
1756 | return -ENOMEM; | ||
1757 | } | ||
1758 | |||
1759 | error = generic_ops_register(); | ||
1760 | if (error) | ||
1761 | goto err_put; | ||
1762 | |||
1763 | /* Don't forget the systab entry */ | ||
1764 | error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); | ||
1765 | if (error) { | ||
1766 | printk(KERN_ERR | ||
1767 | "efivars: Sysfs attribute export failed with error %d.\n", | ||
1768 | error); | ||
1769 | goto err_unregister; | ||
1770 | } | ||
1771 | |||
1772 | return 0; | ||
1773 | |||
1774 | err_unregister: | ||
1775 | generic_ops_unregister(); | ||
1776 | err_put: | ||
1777 | kobject_put(efi_kobj); | ||
1778 | return error; | ||
1779 | } | ||
1780 | |||
1781 | static void __exit | ||
1782 | efivars_exit(void) | ||
1783 | { | ||
1784 | cancel_work_sync(&efivar_work); | ||
1785 | |||
1786 | if (efi_enabled(EFI_RUNTIME_SERVICES)) { | ||
1787 | generic_ops_unregister(); | ||
1788 | kobject_put(efi_kobj); | ||
1789 | } | ||
1790 | } | ||
1791 | |||
1792 | module_init(efivars_init); | ||
1793 | module_exit(efivars_exit); | ||
1794 | |||
diff --git a/fs/efivarfs/Kconfig b/fs/efivarfs/Kconfig index 1fb2b7f849f3..367bbb10c543 100644 --- a/fs/efivarfs/Kconfig +++ b/fs/efivarfs/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config EFIVAR_FS | 1 | config EFIVAR_FS |
2 | tristate "EFI Variable filesystem" | 2 | tristate "EFI Variable filesystem" |
3 | depends on EFI_VARS | 3 | depends on EFI |
4 | help | 4 | help |
5 | efivarfs is a replacement filesystem for the old EFI | 5 | efivarfs is a replacement filesystem for the old EFI |
6 | variable support via sysfs, as it doesn't suffer from the | 6 | variable support via sysfs, as it doesn't suffer from the |
diff --git a/include/linux/efi.h b/include/linux/efi.h index 8ff6ec1ac046..2fc816682714 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -742,7 +742,6 @@ utf16_strlen(efi_char16_t *s) | |||
742 | return utf16_strnlen(s, ~0UL); | 742 | return utf16_strnlen(s, ~0UL); |
743 | } | 743 | } |
744 | 744 | ||
745 | #if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE) | ||
746 | /* | 745 | /* |
747 | * Return the number of bytes is the length of this string | 746 | * Return the number of bytes is the length of this string |
748 | * Note: this is NOT the same as the number of unicode characters | 747 | * Note: this is NOT the same as the number of unicode characters |
@@ -872,8 +871,10 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, | |||
872 | 871 | ||
873 | bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); | 872 | bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len); |
874 | 873 | ||
874 | extern struct work_struct efivar_work; | ||
875 | void efivar_run_worker(void); | 875 | void efivar_run_worker(void); |
876 | 876 | ||
877 | #if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE) | ||
877 | int efivars_sysfs_init(void); | 878 | int efivars_sysfs_init(void); |
878 | 879 | ||
879 | #endif /* CONFIG_EFI_VARS */ | 880 | #endif /* CONFIG_EFI_VARS */ |