Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0+
2 : : /*
3 : : * Originally from efivars.c,
4 : : *
5 : : * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
6 : : * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
7 : : *
8 : : * This code takes all variables accessible from EFI runtime and
9 : : * exports them via sysfs
10 : : */
11 : :
12 : : #include <linux/efi.h>
13 : : #include <linux/module.h>
14 : : #include <linux/slab.h>
15 : : #include <linux/ucs2_string.h>
16 : : #include <linux/compat.h>
17 : :
18 : : #define EFIVARS_VERSION "0.08"
19 : : #define EFIVARS_DATE "2004-May-17"
20 : :
21 : : MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
22 : : MODULE_DESCRIPTION("sysfs interface to EFI Variables");
23 : : MODULE_LICENSE("GPL");
24 : : MODULE_VERSION(EFIVARS_VERSION);
25 : : MODULE_ALIAS("platform:efivars");
26 : :
27 : : LIST_HEAD(efivar_sysfs_list);
28 : : EXPORT_SYMBOL_GPL(efivar_sysfs_list);
29 : :
30 : : static struct kset *efivars_kset;
31 : :
32 : : static struct bin_attribute *efivars_new_var;
33 : : static struct bin_attribute *efivars_del_var;
34 : :
35 : : struct compat_efi_variable {
36 : : efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
37 : : efi_guid_t VendorGuid;
38 : : __u32 DataSize;
39 : : __u8 Data[1024];
40 : : __u32 Status;
41 : : __u32 Attributes;
42 : : } __packed;
43 : :
44 : : struct efivar_attribute {
45 : : struct attribute attr;
46 : : ssize_t (*show) (struct efivar_entry *entry, char *buf);
47 : : ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
48 : : };
49 : :
50 : : #define EFIVAR_ATTR(_name, _mode, _show, _store) \
51 : : struct efivar_attribute efivar_attr_##_name = { \
52 : : .attr = {.name = __stringify(_name), .mode = _mode}, \
53 : : .show = _show, \
54 : : .store = _store, \
55 : : };
56 : :
57 : : #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
58 : : #define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj)
59 : :
60 : : /*
61 : : * Prototype for sysfs creation function
62 : : */
63 : : static int
64 : : efivar_create_sysfs_entry(struct efivar_entry *new_var);
65 : :
66 : : static ssize_t
67 : 0 : efivar_guid_read(struct efivar_entry *entry, char *buf)
68 : : {
69 : 0 : struct efi_variable *var = &entry->var;
70 : 0 : char *str = buf;
71 : :
72 [ # # ]: 0 : if (!entry || !buf)
73 : : return 0;
74 : :
75 : 0 : efi_guid_to_str(&var->VendorGuid, str);
76 : 0 : str += strlen(str);
77 : 0 : str += sprintf(str, "\n");
78 : :
79 : 0 : return str - buf;
80 : : }
81 : :
82 : : static ssize_t
83 : 0 : efivar_attr_read(struct efivar_entry *entry, char *buf)
84 : : {
85 : 0 : struct efi_variable *var = &entry->var;
86 : 0 : unsigned long size = sizeof(var->Data);
87 : 0 : char *str = buf;
88 : 0 : int ret;
89 : :
90 [ # # ]: 0 : if (!entry || !buf)
91 : : return -EINVAL;
92 : :
93 : 0 : ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
94 : 0 : var->DataSize = size;
95 [ # # ]: 0 : if (ret)
96 : : return -EIO;
97 : :
98 [ # # ]: 0 : if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
99 : 0 : str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
100 [ # # ]: 0 : if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
101 : 0 : str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
102 [ # # ]: 0 : if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
103 : 0 : str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
104 [ # # ]: 0 : if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
105 : 0 : str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
106 [ # # ]: 0 : if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
107 : 0 : str += sprintf(str,
108 : : "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
109 [ # # ]: 0 : if (var->Attributes &
110 : : EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
111 : 0 : str += sprintf(str,
112 : : "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
113 [ # # ]: 0 : if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
114 : 0 : str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
115 : 0 : return str - buf;
116 : : }
117 : :
118 : : static ssize_t
119 : 0 : efivar_size_read(struct efivar_entry *entry, char *buf)
120 : : {
121 : 0 : struct efi_variable *var = &entry->var;
122 : 0 : unsigned long size = sizeof(var->Data);
123 : 0 : char *str = buf;
124 : 0 : int ret;
125 : :
126 [ # # ]: 0 : if (!entry || !buf)
127 : : return -EINVAL;
128 : :
129 : 0 : ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
130 : 0 : var->DataSize = size;
131 [ # # ]: 0 : if (ret)
132 : : return -EIO;
133 : :
134 : 0 : str += sprintf(str, "0x%lx\n", var->DataSize);
135 : 0 : return str - buf;
136 : : }
137 : :
138 : : static ssize_t
139 : 0 : efivar_data_read(struct efivar_entry *entry, char *buf)
140 : : {
141 : 0 : struct efi_variable *var = &entry->var;
142 : 0 : unsigned long size = sizeof(var->Data);
143 : 0 : int ret;
144 : :
145 [ # # ]: 0 : if (!entry || !buf)
146 : : return -EINVAL;
147 : :
148 : 0 : ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
149 : 0 : var->DataSize = size;
150 [ # # ]: 0 : if (ret)
151 : : return -EIO;
152 : :
153 : 0 : memcpy(buf, var->Data, var->DataSize);
154 : 0 : return var->DataSize;
155 : : }
156 : :
157 : : static inline int
158 : 0 : sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
159 : : unsigned long size, u32 attributes, u8 *data)
160 : : {
161 : : /*
162 : : * If only updating the variable data, then the name
163 : : * and guid should remain the same
164 : : */
165 [ # # ]: 0 : if (memcmp(name, var->VariableName, sizeof(var->VariableName)) ||
166 [ # # ]: 0 : efi_guidcmp(vendor, var->VendorGuid)) {
167 : 0 : printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
168 : 0 : return -EINVAL;
169 : : }
170 : :
171 [ # # ]: 0 : if ((size <= 0) || (attributes == 0)){
172 : 0 : printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
173 : 0 : return -EINVAL;
174 : : }
175 : :
176 [ # # # # ]: 0 : if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
177 : 0 : efivar_validate(vendor, name, data, size) == false) {
178 : 0 : printk(KERN_ERR "efivars: Malformed variable content\n");
179 : 0 : return -EINVAL;
180 : : }
181 : :
182 : : return 0;
183 : : }
184 : :
185 : : static void
186 : 0 : copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src)
187 : : {
188 : 0 : memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN);
189 : 0 : memcpy(dst->Data, src->Data, sizeof(src->Data));
190 : :
191 : 0 : dst->VendorGuid = src->VendorGuid;
192 : 0 : dst->DataSize = src->DataSize;
193 : 0 : dst->Attributes = src->Attributes;
194 : 0 : }
195 : :
196 : : /*
197 : : * We allow each variable to be edited via rewriting the
198 : : * entire efi variable structure.
199 : : */
200 : : static ssize_t
201 : 0 : efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
202 : : {
203 : 0 : struct efi_variable *new_var, *var = &entry->var;
204 : 0 : efi_char16_t *name;
205 : 0 : unsigned long size;
206 : 0 : efi_guid_t vendor;
207 : 0 : u32 attributes;
208 : 0 : u8 *data;
209 : 0 : int err;
210 : :
211 [ # # ]: 0 : if (!entry || !buf)
212 : : return -EINVAL;
213 : :
214 [ # # # # ]: 0 : if (in_compat_syscall()) {
215 : 0 : struct compat_efi_variable *compat;
216 : :
217 [ # # ]: 0 : if (count != sizeof(*compat))
218 : : return -EINVAL;
219 : :
220 : 0 : compat = (struct compat_efi_variable *)buf;
221 : 0 : attributes = compat->Attributes;
222 : 0 : vendor = compat->VendorGuid;
223 : 0 : name = compat->VariableName;
224 : 0 : size = compat->DataSize;
225 : 0 : data = compat->Data;
226 : :
227 : 0 : err = sanity_check(var, name, vendor, size, attributes, data);
228 [ # # ]: 0 : if (err)
229 : 0 : return err;
230 : :
231 : 0 : copy_out_compat(&entry->var, compat);
232 : : } else {
233 [ # # ]: 0 : if (count != sizeof(struct efi_variable))
234 : : return -EINVAL;
235 : :
236 : 0 : new_var = (struct efi_variable *)buf;
237 : :
238 : 0 : attributes = new_var->Attributes;
239 : 0 : vendor = new_var->VendorGuid;
240 : 0 : name = new_var->VariableName;
241 : 0 : size = new_var->DataSize;
242 : 0 : data = new_var->Data;
243 : :
244 : 0 : err = sanity_check(var, name, vendor, size, attributes, data);
245 [ # # ]: 0 : if (err)
246 : 0 : return err;
247 : :
248 : 0 : memcpy(&entry->var, new_var, count);
249 : : }
250 : :
251 : 0 : err = efivar_entry_set(entry, attributes, size, data, NULL);
252 [ # # ]: 0 : if (err) {
253 : 0 : printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
254 : 0 : return -EIO;
255 : : }
256 : :
257 : 0 : return count;
258 : : }
259 : :
260 : : static ssize_t
261 : 0 : efivar_show_raw(struct efivar_entry *entry, char *buf)
262 : : {
263 : 0 : struct efi_variable *var = &entry->var;
264 : 0 : struct compat_efi_variable *compat;
265 : 0 : unsigned long datasize = sizeof(var->Data);
266 : 0 : size_t size;
267 : 0 : int ret;
268 : :
269 [ # # ]: 0 : if (!entry || !buf)
270 : : return 0;
271 : :
272 : 0 : ret = efivar_entry_get(entry, &var->Attributes, &datasize, var->Data);
273 : 0 : var->DataSize = datasize;
274 [ # # ]: 0 : if (ret)
275 : : return -EIO;
276 : :
277 [ # # # # ]: 0 : if (in_compat_syscall()) {
278 : 0 : compat = (struct compat_efi_variable *)buf;
279 : :
280 : 0 : size = sizeof(*compat);
281 : 0 : memcpy(compat->VariableName, var->VariableName,
282 : : EFI_VAR_NAME_LEN);
283 : 0 : memcpy(compat->Data, var->Data, sizeof(compat->Data));
284 : :
285 : 0 : compat->VendorGuid = var->VendorGuid;
286 : 0 : compat->DataSize = var->DataSize;
287 : 0 : compat->Attributes = var->Attributes;
288 : : } else {
289 : 0 : size = sizeof(*var);
290 : 0 : memcpy(buf, var, size);
291 : : }
292 : :
293 : 0 : return size;
294 : : }
295 : :
296 : : /*
297 : : * Generic read/write functions that call the specific functions of
298 : : * the attributes...
299 : : */
300 : 0 : static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
301 : : char *buf)
302 : : {
303 : 0 : struct efivar_entry *var = to_efivar_entry(kobj);
304 : 0 : struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
305 : 0 : ssize_t ret = -EIO;
306 : :
307 [ # # ]: 0 : if (!capable(CAP_SYS_ADMIN))
308 : : return -EACCES;
309 : :
310 [ # # ]: 0 : if (efivar_attr->show) {
311 : 0 : ret = efivar_attr->show(var, buf);
312 : : }
313 : : return ret;
314 : : }
315 : :
316 : 0 : static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
317 : : const char *buf, size_t count)
318 : : {
319 : 0 : struct efivar_entry *var = to_efivar_entry(kobj);
320 : 0 : struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
321 : 0 : ssize_t ret = -EIO;
322 : :
323 [ # # ]: 0 : if (!capable(CAP_SYS_ADMIN))
324 : : return -EACCES;
325 : :
326 [ # # ]: 0 : if (efivar_attr->store)
327 : 0 : ret = efivar_attr->store(var, buf, count);
328 : :
329 : : return ret;
330 : : }
331 : :
332 : : static const struct sysfs_ops efivar_attr_ops = {
333 : : .show = efivar_attr_show,
334 : : .store = efivar_attr_store,
335 : : };
336 : :
337 : 0 : static void efivar_release(struct kobject *kobj)
338 : : {
339 : 0 : struct efivar_entry *var = to_efivar_entry(kobj);
340 : 0 : kfree(var);
341 : 0 : }
342 : :
343 : : static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
344 : : static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
345 : : static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
346 : : static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
347 : : static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
348 : :
349 : : static struct attribute *def_attrs[] = {
350 : : &efivar_attr_guid.attr,
351 : : &efivar_attr_size.attr,
352 : : &efivar_attr_attributes.attr,
353 : : &efivar_attr_data.attr,
354 : : &efivar_attr_raw_var.attr,
355 : : NULL,
356 : : };
357 : :
358 : : static struct kobj_type efivar_ktype = {
359 : : .release = efivar_release,
360 : : .sysfs_ops = &efivar_attr_ops,
361 : : .default_attrs = def_attrs,
362 : : };
363 : :
364 : 0 : static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
365 : : struct bin_attribute *bin_attr,
366 : : char *buf, loff_t pos, size_t count)
367 : : {
368 : 0 : struct compat_efi_variable *compat = (struct compat_efi_variable *)buf;
369 : 0 : struct efi_variable *new_var = (struct efi_variable *)buf;
370 : 0 : struct efivar_entry *new_entry;
371 [ # # ]: 0 : bool need_compat = in_compat_syscall();
372 : 0 : efi_char16_t *name;
373 : 0 : unsigned long size;
374 : 0 : u32 attributes;
375 : 0 : u8 *data;
376 : 0 : int err;
377 : :
378 [ # # ]: 0 : if (!capable(CAP_SYS_ADMIN))
379 : : return -EACCES;
380 : :
381 [ # # ]: 0 : if (need_compat) {
382 [ # # ]: 0 : if (count != sizeof(*compat))
383 : : return -EINVAL;
384 : :
385 : 0 : attributes = compat->Attributes;
386 : 0 : name = compat->VariableName;
387 : 0 : size = compat->DataSize;
388 : 0 : data = compat->Data;
389 : : } else {
390 [ # # ]: 0 : if (count != sizeof(*new_var))
391 : : return -EINVAL;
392 : :
393 : 0 : attributes = new_var->Attributes;
394 : 0 : name = new_var->VariableName;
395 : 0 : size = new_var->DataSize;
396 : 0 : data = new_var->Data;
397 : : }
398 : :
399 [ # # # # ]: 0 : if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
400 : 0 : efivar_validate(new_var->VendorGuid, name, data,
401 : : size) == false) {
402 : 0 : printk(KERN_ERR "efivars: Malformed variable content\n");
403 : 0 : return -EINVAL;
404 : : }
405 : :
406 : 0 : new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
407 [ # # ]: 0 : if (!new_entry)
408 : : return -ENOMEM;
409 : :
410 [ # # ]: 0 : if (need_compat)
411 : 0 : copy_out_compat(&new_entry->var, compat);
412 : : else
413 : 0 : memcpy(&new_entry->var, new_var, sizeof(*new_var));
414 : :
415 : 0 : err = efivar_entry_set(new_entry, attributes, size,
416 : : data, &efivar_sysfs_list);
417 [ # # ]: 0 : if (err) {
418 [ # # ]: 0 : if (err == -EEXIST)
419 : 0 : err = -EINVAL;
420 : 0 : goto out;
421 : : }
422 : :
423 [ # # ]: 0 : if (efivar_create_sysfs_entry(new_entry)) {
424 : 0 : printk(KERN_WARNING "efivars: failed to create sysfs entry.\n");
425 : 0 : kfree(new_entry);
426 : : }
427 : 0 : return count;
428 : :
429 : : out:
430 : 0 : kfree(new_entry);
431 : 0 : return err;
432 : : }
433 : :
434 : 0 : static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
435 : : struct bin_attribute *bin_attr,
436 : : char *buf, loff_t pos, size_t count)
437 : : {
438 : 0 : struct efi_variable *del_var = (struct efi_variable *)buf;
439 : 0 : struct compat_efi_variable *compat;
440 : 0 : struct efivar_entry *entry;
441 : 0 : efi_char16_t *name;
442 : 0 : efi_guid_t vendor;
443 : 0 : int err = 0;
444 : :
445 [ # # ]: 0 : if (!capable(CAP_SYS_ADMIN))
446 : : return -EACCES;
447 : :
448 [ # # # # ]: 0 : if (in_compat_syscall()) {
449 [ # # ]: 0 : if (count != sizeof(*compat))
450 : : return -EINVAL;
451 : :
452 : 0 : compat = (struct compat_efi_variable *)buf;
453 : 0 : name = compat->VariableName;
454 : 0 : vendor = compat->VendorGuid;
455 : : } else {
456 [ # # ]: 0 : if (count != sizeof(*del_var))
457 : : return -EINVAL;
458 : :
459 : 0 : name = del_var->VariableName;
460 : 0 : vendor = del_var->VendorGuid;
461 : : }
462 : :
463 [ # # ]: 0 : if (efivar_entry_iter_begin())
464 : : return -EINTR;
465 : 0 : entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);
466 [ # # ]: 0 : if (!entry)
467 : : err = -EINVAL;
468 [ # # ]: 0 : else if (__efivar_entry_delete(entry))
469 : : err = -EIO;
470 : :
471 : 0 : if (err) {
472 : 0 : efivar_entry_iter_end();
473 : 0 : return err;
474 : : }
475 : :
476 [ # # ]: 0 : if (!entry->scanning) {
477 : 0 : efivar_entry_iter_end();
478 : 0 : efivar_unregister(entry);
479 : : } else
480 : 0 : efivar_entry_iter_end();
481 : :
482 : : /* It's dead Jim.... */
483 : 0 : return count;
484 : : }
485 : :
486 : : /**
487 : : * efivar_create_sysfs_entry - create a new entry in sysfs
488 : : * @new_var: efivar entry to create
489 : : *
490 : : * Returns 0 on success, negative error code on failure
491 : : */
492 : : static int
493 : 0 : efivar_create_sysfs_entry(struct efivar_entry *new_var)
494 : : {
495 : 0 : int short_name_size;
496 : 0 : char *short_name;
497 : 0 : unsigned long utf8_name_size;
498 : 0 : efi_char16_t *variable_name = new_var->var.VariableName;
499 : 0 : int ret;
500 : :
501 : : /*
502 : : * Length of the variable bytes in UTF8, plus the '-' separator,
503 : : * plus the GUID, plus trailing NUL
504 : : */
505 : 0 : utf8_name_size = ucs2_utf8size(variable_name);
506 : 0 : short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
507 : :
508 [ # # ]: 0 : short_name = kmalloc(short_name_size, GFP_KERNEL);
509 [ # # ]: 0 : if (!short_name)
510 : : return -ENOMEM;
511 : :
512 : 0 : ucs2_as_utf8(short_name, variable_name, short_name_size);
513 : :
514 : : /* This is ugly, but necessary to separate one vendor's
515 : : private variables from another's. */
516 : 0 : short_name[utf8_name_size] = '-';
517 : 0 : efi_guid_to_str(&new_var->var.VendorGuid,
518 : 0 : short_name + utf8_name_size + 1);
519 : :
520 : 0 : new_var->kobj.kset = efivars_kset;
521 : :
522 : 0 : ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
523 : : NULL, "%s", short_name);
524 : 0 : kfree(short_name);
525 [ # # ]: 0 : if (ret)
526 : : return ret;
527 : :
528 : 0 : kobject_uevent(&new_var->kobj, KOBJ_ADD);
529 [ # # ]: 0 : if (efivar_entry_add(new_var, &efivar_sysfs_list)) {
530 : 0 : efivar_unregister(new_var);
531 : 0 : return -EINTR;
532 : : }
533 : :
534 : : return 0;
535 : : }
536 : :
537 : : static int
538 : 0 : create_efivars_bin_attributes(void)
539 : : {
540 : 0 : struct bin_attribute *attr;
541 : 0 : int error;
542 : :
543 : : /* new_var */
544 : 0 : attr = kzalloc(sizeof(*attr), GFP_KERNEL);
545 [ # # ]: 0 : if (!attr)
546 : : return -ENOMEM;
547 : :
548 : 0 : attr->attr.name = "new_var";
549 : 0 : attr->attr.mode = 0200;
550 : 0 : attr->write = efivar_create;
551 : 0 : efivars_new_var = attr;
552 : :
553 : : /* del_var */
554 : 0 : attr = kzalloc(sizeof(*attr), GFP_KERNEL);
555 [ # # ]: 0 : if (!attr) {
556 : 0 : error = -ENOMEM;
557 : 0 : goto out_free;
558 : : }
559 : 0 : attr->attr.name = "del_var";
560 : 0 : attr->attr.mode = 0200;
561 : 0 : attr->write = efivar_delete;
562 : 0 : efivars_del_var = attr;
563 : :
564 : 0 : sysfs_bin_attr_init(efivars_new_var);
565 : 0 : sysfs_bin_attr_init(efivars_del_var);
566 : :
567 : : /* Register */
568 : 0 : error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var);
569 [ # # ]: 0 : if (error) {
570 : 0 : printk(KERN_ERR "efivars: unable to create new_var sysfs file"
571 : : " due to error %d\n", error);
572 : 0 : goto out_free;
573 : : }
574 : :
575 : 0 : error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var);
576 [ # # ]: 0 : if (error) {
577 : 0 : printk(KERN_ERR "efivars: unable to create del_var sysfs file"
578 : : " due to error %d\n", error);
579 : 0 : sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
580 : 0 : goto out_free;
581 : : }
582 : :
583 : : return 0;
584 : 0 : out_free:
585 : 0 : kfree(efivars_del_var);
586 : 0 : efivars_del_var = NULL;
587 : 0 : kfree(efivars_new_var);
588 : 0 : efivars_new_var = NULL;
589 : 0 : return error;
590 : : }
591 : :
592 : 0 : static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor,
593 : : unsigned long name_size, void *data)
594 : : {
595 : 0 : struct efivar_entry *entry = data;
596 : :
597 [ # # ]: 0 : if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false))
598 : : return 0;
599 : :
600 : 0 : memcpy(entry->var.VariableName, name, name_size);
601 : 0 : memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
602 : :
603 : 0 : return 1;
604 : : }
605 : :
606 : 0 : static void efivar_update_sysfs_entries(struct work_struct *work)
607 : : {
608 : 0 : struct efivar_entry *entry;
609 : 0 : int err;
610 : :
611 : : /* Add new sysfs entries */
612 : 0 : while (1) {
613 : 0 : entry = kzalloc(sizeof(*entry), GFP_KERNEL);
614 [ # # ]: 0 : if (!entry)
615 : : return;
616 : :
617 : 0 : err = efivar_init(efivar_update_sysfs_entry, entry,
618 : : false, &efivar_sysfs_list);
619 [ # # ]: 0 : if (!err)
620 : : break;
621 : :
622 : 0 : efivar_create_sysfs_entry(entry);
623 : : }
624 : :
625 : 0 : kfree(entry);
626 : : }
627 : :
628 : 0 : static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
629 : : unsigned long name_size, void *data)
630 : : {
631 : 0 : struct efivar_entry *entry;
632 : :
633 : 0 : entry = kzalloc(sizeof(*entry), GFP_KERNEL);
634 [ # # ]: 0 : if (!entry)
635 : : return -ENOMEM;
636 : :
637 : 0 : memcpy(entry->var.VariableName, name, name_size);
638 : 0 : memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
639 : :
640 : 0 : efivar_create_sysfs_entry(entry);
641 : :
642 : 0 : return 0;
643 : : }
644 : :
645 : 0 : static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
646 : : {
647 : 0 : int err = efivar_entry_remove(entry);
648 : :
649 [ # # ]: 0 : if (err)
650 : : return err;
651 : 0 : efivar_unregister(entry);
652 : 0 : return 0;
653 : : }
654 : :
655 : 0 : static void efivars_sysfs_exit(void)
656 : : {
657 : : /* Remove all entries and destroy */
658 : 0 : int err;
659 : :
660 : 0 : err = __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list,
661 : : NULL, NULL);
662 [ # # ]: 0 : if (err) {
663 : 0 : pr_err("efivars: Failed to destroy sysfs entries\n");
664 : 0 : return;
665 : : }
666 : :
667 [ # # ]: 0 : if (efivars_new_var)
668 : 0 : sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
669 [ # # ]: 0 : if (efivars_del_var)
670 : 0 : sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var);
671 : 0 : kfree(efivars_new_var);
672 : 0 : kfree(efivars_del_var);
673 : 0 : kset_unregister(efivars_kset);
674 : : }
675 : :
676 : 3 : int efivars_sysfs_init(void)
677 : : {
678 : 3 : struct kobject *parent_kobj = efivars_kobject();
679 : 3 : int error = 0;
680 : :
681 [ - + ]: 3 : if (!efi_enabled(EFI_RUNTIME_SERVICES))
682 : : return -ENODEV;
683 : :
684 : : /* No efivars has been registered yet */
685 [ # # ]: 0 : if (!parent_kobj)
686 : : return 0;
687 : :
688 : 0 : printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
689 : : EFIVARS_DATE);
690 : :
691 : 0 : efivars_kset = kset_create_and_add("vars", NULL, parent_kobj);
692 [ # # ]: 0 : if (!efivars_kset) {
693 : 0 : printk(KERN_ERR "efivars: Subsystem registration failed.\n");
694 : 0 : return -ENOMEM;
695 : : }
696 : :
697 : 0 : efivar_init(efivars_sysfs_callback, NULL, true, &efivar_sysfs_list);
698 : :
699 : 0 : error = create_efivars_bin_attributes();
700 [ # # ]: 0 : if (error) {
701 : 0 : efivars_sysfs_exit();
702 : 0 : return error;
703 : : }
704 : :
705 : 0 : INIT_WORK(&efivar_work, efivar_update_sysfs_entries);
706 : :
707 : 0 : return 0;
708 : : }
709 : : EXPORT_SYMBOL_GPL(efivars_sysfs_init);
710 : :
711 : : module_init(efivars_sysfs_init);
712 : : module_exit(efivars_sysfs_exit);
|