Blame view

drivers/firmware/efivars.c 26.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  /*
   * EFI Variables - efivars.c
   *
   * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
   * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
   *
   * This code takes all variables accessible from EFI runtime and
   *  exports them via sysfs
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   *
   * Changelog:
   *
   *  17 May 2004 - Matt Domsch <Matt_Domsch@dell.com>
   *   remove check for efi_enabled in exit
   *   add MODULE_VERSION
   *
   *  26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com>
   *   minor bug fixes
   *
   *  21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com)
   *   converted driver to export variable information via sysfs
   *   and moved to drivers/firmware directory
   *   bumped revision number to v0.07 to reflect conversion & move
   *
   *  10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
   *   fix locking per Peter Chubb's findings
   *
   *  25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
   *   move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
   *
   *  12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
   *   use list_for_each_safe when deleting vars.
   *   remove ifdef CONFIG_SMP around include <linux/smp.h>
   *   v0.04 release to linux-ia64@linuxia64.org
   *
   *  20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
   *   Moved vars from /proc/efi to /proc/efi/vars, and made
   *   efi.c own the /proc/efi directory.
   *   v0.03 release to linux-ia64@linuxia64.org
   *
   *  26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
   *   At the request of Stephane, moved ownership of /proc/efi
   *   to efi.c, and now efivars lives under /proc/efi/vars.
   *
   *  12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
   *   Feedback received from Stephane Eranian incorporated.
   *   efivar_write() checks copy_from_user() return value.
   *   efivar_read/write() returns proper errno.
   *   v0.02 release to linux-ia64@linuxia64.org
   *
   *  26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
   *   v0.01 release to linux-ia64@linuxia64.org
   */
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
67
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
  #include <linux/mm.h>
  #include <linux/module.h>
  #include <linux/string.h>
  #include <linux/smp.h>
  #include <linux/efi.h>
  #include <linux/sysfs.h>
  #include <linux/kobject.h>
  #include <linux/device.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
79
  #include <linux/slab.h>
5ee9c198a   Matthew Garrett   efi: Add support ...
80
  #include <linux/pstore.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
87
88
89
90
  
  #include <asm/uaccess.h>
  
  #define EFIVARS_VERSION "0.08"
  #define EFIVARS_DATE "2004-May-17"
  
  MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
  MODULE_DESCRIPTION("sysfs interface to EFI Variables");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(EFIVARS_VERSION);
5ee9c198a   Matthew Garrett   efi: Add support ...
91
  #define DUMP_NAME_LEN 52
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  /*
   * The maximum size of VariableName + Data = 1024
   * Therefore, it's reasonable to save that much
   * space in each part of the structure,
   * and we use a page for reading/writing.
   */
  
  struct efi_variable {
  	efi_char16_t  VariableName[1024/sizeof(efi_char16_t)];
  	efi_guid_t    VendorGuid;
  	unsigned long DataSize;
  	__u8          Data[1024];
  	efi_status_t  Status;
  	__u32         Attributes;
  } __attribute__((packed));
  
  
  struct efivar_entry {
4142ef146   Mike Waychison   efivars: paramete...
110
  	struct efivars *efivars;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
  	struct efi_variable var;
  	struct list_head list;
  	struct kobject kobj;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
  struct efivar_attribute {
  	struct attribute attr;
  	ssize_t (*show) (struct efivar_entry *entry, char *buf);
  	ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
  };
7644c16c7   Mike Waychison   efivars: Introduc...
120
121
122
123
  #define PSTORE_EFI_ATTRIBUTES \
  	(EFI_VARIABLE_NON_VOLATILE | \
  	 EFI_VARIABLE_BOOTSERVICE_ACCESS | \
  	 EFI_VARIABLE_RUNTIME_ACCESS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
  #define EFIVAR_ATTR(_name, _mode, _show, _store) \
  struct efivar_attribute efivar_attr_##_name = { \
7b595756e   Tejun Heo   sysfs: kill unnec...
127
  	.attr = {.name = __stringify(_name), .mode = _mode}, \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
  	.show = _show, \
  	.store = _store, \
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
  #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
  #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
  
  /*
   * Prototype for sysfs creation function
   */
  static int
4142ef146   Mike Waychison   efivars: paramete...
138
139
140
141
  efivar_create_sysfs_entry(struct efivars *efivars,
  			  unsigned long variable_name_size,
  			  efi_char16_t *variable_name,
  			  efi_guid_t *vendor_guid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
  
  /* Return the number of unicode characters in data */
  static unsigned long
a29409083   Mike Waychison   efivars: String f...
145
  utf16_strnlen(efi_char16_t *s, size_t maxlength)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  {
  	unsigned long length = 0;
a29409083   Mike Waychison   efivars: String f...
148
  	while (*s++ != 0 && length < maxlength)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
  		length++;
  	return length;
  }
b728a5c80   Tony Luck   efivars: fix warn...
152
  static inline unsigned long
a29409083   Mike Waychison   efivars: String f...
153
154
155
156
  utf16_strlen(efi_char16_t *s)
  {
  	return utf16_strnlen(s, ~0UL);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
  /*
   * Return the number of bytes is the length of this string
   * Note: this is NOT the same as the number of unicode characters
   */
  static inline unsigned long
a29409083   Mike Waychison   efivars: String f...
162
  utf16_strsize(efi_char16_t *data, unsigned long maxlength)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  {
a29409083   Mike Waychison   efivars: String f...
164
  	return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
828aa1f00   Mike Waychison   efivars: introduc...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  static inline int
  utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len)
  {
  	while (1) {
  		if (len == 0)
  			return 0;
  		if (*a < *b)
  			return -1;
  		if (*a > *b)
  			return 1;
  		if (*a == 0) /* implies *b == 0 */
  			return 0;
  		a++;
  		b++;
  		len--;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  static efi_status_t
5ee9c198a   Matthew Garrett   efi: Add support ...
184
  get_var_data_locked(struct efivars *efivars, struct efi_variable *var)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  {
  	efi_status_t status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	var->DataSize = 1024;
3295814d8   Mike Waychison   efivars: Paramete...
188
189
190
191
192
  	status = efivars->ops->get_variable(var->VariableName,
  					    &var->VendorGuid,
  					    &var->Attributes,
  					    &var->DataSize,
  					    var->Data);
5ee9c198a   Matthew Garrett   efi: Add support ...
193
194
195
196
197
198
199
200
201
202
  	return status;
  }
  
  static efi_status_t
  get_var_data(struct efivars *efivars, struct efi_variable *var)
  {
  	efi_status_t status;
  
  	spin_lock(&efivars->lock);
  	status = get_var_data_locked(efivars, var);
29422693c   Mike Waychison   efivars: move efi...
203
  	spin_unlock(&efivars->lock);
5ee9c198a   Matthew Garrett   efi: Add support ...
204

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  	if (status != EFI_SUCCESS) {
  		printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!
  ",
  			status);
  	}
  	return status;
  }
  
  static ssize_t
  efivar_guid_read(struct efivar_entry *entry, char *buf)
  {
  	struct efi_variable *var = &entry->var;
  	char *str = buf;
  
  	if (!entry || !buf)
  		return 0;
  
  	efi_guid_unparse(&var->VendorGuid, str);
  	str += strlen(str);
  	str += sprintf(str, "
  ");
  
  	return str - buf;
  }
  
  static ssize_t
  efivar_attr_read(struct efivar_entry *entry, char *buf)
  {
  	struct efi_variable *var = &entry->var;
  	char *str = buf;
  	efi_status_t status;
  
  	if (!entry || !buf)
  		return -EINVAL;
4142ef146   Mike Waychison   efivars: paramete...
239
  	status = get_var_data(entry->efivars, var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  	if (status != EFI_SUCCESS)
  		return -EIO;
  
  	if (var->Attributes & 0x1)
  		str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE
  ");
  	if (var->Attributes & 0x2)
  		str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS
  ");
  	if (var->Attributes & 0x4)
  		str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS
  ");
  	return str - buf;
  }
  
  static ssize_t
  efivar_size_read(struct efivar_entry *entry, char *buf)
  {
  	struct efi_variable *var = &entry->var;
  	char *str = buf;
  	efi_status_t status;
  
  	if (!entry || !buf)
  		return -EINVAL;
4142ef146   Mike Waychison   efivars: paramete...
264
  	status = get_var_data(entry->efivars, var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  	if (status != EFI_SUCCESS)
  		return -EIO;
  
  	str += sprintf(str, "0x%lx
  ", var->DataSize);
  	return str - buf;
  }
  
  static ssize_t
  efivar_data_read(struct efivar_entry *entry, char *buf)
  {
  	struct efi_variable *var = &entry->var;
  	efi_status_t status;
  
  	if (!entry || !buf)
  		return -EINVAL;
4142ef146   Mike Waychison   efivars: paramete...
281
  	status = get_var_data(entry->efivars, var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  	if (status != EFI_SUCCESS)
  		return -EIO;
  
  	memcpy(buf, var->Data, var->DataSize);
  	return var->DataSize;
  }
  /*
   * We allow each variable to be edited via rewriting the
   * entire efi variable structure.
   */
  static ssize_t
  efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
  {
  	struct efi_variable *new_var, *var = &entry->var;
4142ef146   Mike Waychison   efivars: paramete...
296
  	struct efivars *efivars = entry->efivars;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  	efi_status_t status = EFI_NOT_FOUND;
  
  	if (count != sizeof(struct efi_variable))
  		return -EINVAL;
  
  	new_var = (struct efi_variable *)buf;
  	/*
  	 * If only updating the variable data, then the name
  	 * and guid should remain the same
  	 */
  	if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
  		efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
  		printk(KERN_ERR "efivars: Cannot edit the wrong variable!
  ");
  		return -EINVAL;
  	}
  
  	if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
  		printk(KERN_ERR "efivars: DataSize & Attributes must be valid!
  ");
  		return -EINVAL;
  	}
29422693c   Mike Waychison   efivars: move efi...
319
  	spin_lock(&efivars->lock);
3295814d8   Mike Waychison   efivars: Paramete...
320
321
322
323
324
  	status = efivars->ops->set_variable(new_var->VariableName,
  					    &new_var->VendorGuid,
  					    new_var->Attributes,
  					    new_var->DataSize,
  					    new_var->Data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325

29422693c   Mike Waychison   efivars: move efi...
326
  	spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  
  	if (status != EFI_SUCCESS) {
  		printk(KERN_WARNING "efivars: set_variable() failed: status=%lx
  ",
  			status);
  		return -EIO;
  	}
  
  	memcpy(&entry->var, new_var, count);
  	return count;
  }
  
  static ssize_t
  efivar_show_raw(struct efivar_entry *entry, char *buf)
  {
  	struct efi_variable *var = &entry->var;
  	efi_status_t status;
  
  	if (!entry || !buf)
  		return 0;
4142ef146   Mike Waychison   efivars: paramete...
347
  	status = get_var_data(entry->efivars, var);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
353
354
355
356
  	if (status != EFI_SUCCESS)
  		return -EIO;
  
  	memcpy(buf, var, sizeof(*var));
  	return sizeof(*var);
  }
  
  /*
   * Generic read/write functions that call the specific functions of
70f23fd66   Justin P. Mattock   treewide: fix a f...
357
   * the attributes...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
361
362
363
   */
  static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
  				char *buf)
  {
  	struct efivar_entry *var = to_efivar_entry(kobj);
  	struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
70f2817a4   Dmitry Torokhov   [PATCH] sysfs: (r...
364
  	ssize_t ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  
  	if (efivar_attr->show) {
  		ret = efivar_attr->show(var, buf);
  	}
  	return ret;
  }
  
  static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
  				const char *buf, size_t count)
  {
  	struct efivar_entry *var = to_efivar_entry(kobj);
  	struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
70f2817a4   Dmitry Torokhov   [PATCH] sysfs: (r...
380
  	ssize_t ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
387
388
389
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  
  	if (efivar_attr->store)
  		ret = efivar_attr->store(var, buf, count);
  
  	return ret;
  }
52cf25d0a   Emese Revfy   Driver core: Cons...
390
  static const struct sysfs_ops efivar_attr_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
396
397
  	.show = efivar_attr_show,
  	.store = efivar_attr_store,
  };
  
  static void efivar_release(struct kobject *kobj)
  {
  	struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  	kfree(var);
  }
  
  static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
  static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
  static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
  static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
  static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
  
  static struct attribute *def_attrs[] = {
  	&efivar_attr_guid.attr,
  	&efivar_attr_size.attr,
  	&efivar_attr_attributes.attr,
  	&efivar_attr_data.attr,
  	&efivar_attr_raw_var.attr,
  	NULL,
  };
e89a4116e   Greg Kroah-Hartman   Driver core: rena...
415
  static struct kobj_type efivar_ktype = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
  	.release = efivar_release,
  	.sysfs_ops = &efivar_attr_ops,
  	.default_attrs = def_attrs,
  };
5ee9c198a   Matthew Garrett   efi: Add support ...
420
  static struct pstore_info efi_pstore_info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
  static inline void
  efivar_unregister(struct efivar_entry *var)
  {
c10997f65   Greg Kroah-Hartman   Kobject: convert ...
424
  	kobject_put(&var->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
  }
5ee9c198a   Matthew Garrett   efi: Add support ...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  #ifdef CONFIG_PSTORE
  
  static int efi_pstore_open(struct pstore_info *psi)
  {
  	struct efivars *efivars = psi->data;
  
  	spin_lock(&efivars->lock);
  	efivars->walk_entry = list_first_entry(&efivars->list,
  					       struct efivar_entry, list);
  	return 0;
  }
  
  static int efi_pstore_close(struct pstore_info *psi)
  {
  	struct efivars *efivars = psi->data;
  
  	spin_unlock(&efivars->lock);
  	return 0;
  }
  
  static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
f6f828513   Kees Cook   pstore: pass allo...
447
448
  			       struct timespec *timespec,
  			       char **buf, struct pstore_info *psi)
5ee9c198a   Matthew Garrett   efi: Add support ...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
  {
  	efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
  	struct efivars *efivars = psi->data;
  	char name[DUMP_NAME_LEN];
  	int i;
  	unsigned int part, size;
  	unsigned long time;
  
  	while (&efivars->walk_entry->list != &efivars->list) {
  		if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid,
  				 vendor)) {
  			for (i = 0; i < DUMP_NAME_LEN; i++) {
  				name[i] = efivars->walk_entry->var.VariableName[i];
  			}
  			if (sscanf(name, "dump-type%u-%u-%lu", type, &part, &time) == 3) {
  				*id = part;
  				timespec->tv_sec = time;
  				timespec->tv_nsec = 0;
  				get_var_data_locked(efivars, &efivars->walk_entry->var);
  				size = efivars->walk_entry->var.DataSize;
f6f828513   Kees Cook   pstore: pass allo...
469
470
471
472
473
  				*buf = kmalloc(size, GFP_KERNEL);
  				if (*buf == NULL)
  					return -ENOMEM;
  				memcpy(*buf, efivars->walk_entry->var.Data,
  				       size);
5ee9c198a   Matthew Garrett   efi: Add support ...
474
475
476
477
478
479
480
481
482
483
  				efivars->walk_entry = list_entry(efivars->walk_entry->list.next,
  					           struct efivar_entry, list);
  				return size;
  			}
  		}
  		efivars->walk_entry = list_entry(efivars->walk_entry->list.next,
  						 struct efivar_entry, list);
  	}
  	return 0;
  }
3d6d8d20e   Kees Cook   pstore: pass reas...
484
485
  static int efi_pstore_write(enum pstore_type_id type,
  		enum kmsg_dump_reason reason, u64 *id,
b238b8fa9   Chen Gong   pstore: make psto...
486
  		unsigned int part, size_t size, struct pstore_info *psi)
5ee9c198a   Matthew Garrett   efi: Add support ...
487
488
489
490
491
492
493
  {
  	char name[DUMP_NAME_LEN];
  	char stub_name[DUMP_NAME_LEN];
  	efi_char16_t efi_name[DUMP_NAME_LEN];
  	efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
  	struct efivars *efivars = psi->data;
  	struct efivar_entry *entry, *found = NULL;
b238b8fa9   Chen Gong   pstore: make psto...
494
  	int i, ret = 0;
5ee9c198a   Matthew Garrett   efi: Add support ...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  
  	sprintf(stub_name, "dump-type%u-%u-", type, part);
  	sprintf(name, "%s%lu", stub_name, get_seconds());
  
  	spin_lock(&efivars->lock);
  
  	for (i = 0; i < DUMP_NAME_LEN; i++)
  		efi_name[i] = stub_name[i];
  
  	/*
  	 * Clean up any entries with the same name
  	 */
  
  	list_for_each_entry(entry, &efivars->list, list) {
  		get_var_data_locked(efivars, &entry->var);
c475594d8   Mike Waychison   efivars: Use stri...
510
511
512
513
514
515
516
517
518
519
520
  		if (efi_guidcmp(entry->var.VendorGuid, vendor))
  			continue;
  		if (utf16_strncmp(entry->var.VariableName, efi_name,
  				  utf16_strlen(efi_name)))
  			continue;
  		/* Needs to be a prefix */
  		if (entry->var.VariableName[utf16_strlen(efi_name)] == 0)
  			continue;
  
  		/* found */
  		found = entry;
7644c16c7   Mike Waychison   efivars: Introduc...
521
522
523
  		efivars->ops->set_variable(entry->var.VariableName,
  					   &entry->var.VendorGuid,
  					   PSTORE_EFI_ATTRIBUTES,
c475594d8   Mike Waychison   efivars: Use stri...
524
  					   0, NULL);
5ee9c198a   Matthew Garrett   efi: Add support ...
525
526
527
528
529
530
531
  	}
  
  	if (found)
  		list_del(&found->list);
  
  	for (i = 0; i < DUMP_NAME_LEN; i++)
  		efi_name[i] = name[i];
7644c16c7   Mike Waychison   efivars: Introduc...
532
  	efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
5ee9c198a   Matthew Garrett   efi: Add support ...
533
534
535
536
537
538
539
540
  				   size, psi->buf);
  
  	spin_unlock(&efivars->lock);
  
  	if (found)
  		efivar_unregister(found);
  
  	if (size)
b238b8fa9   Chen Gong   pstore: make psto...
541
  		ret = efivar_create_sysfs_entry(efivars,
a29409083   Mike Waychison   efivars: String f...
542
543
  					  utf16_strsize(efi_name,
  							DUMP_NAME_LEN * 2),
5ee9c198a   Matthew Garrett   efi: Add support ...
544
  					  efi_name, &vendor);
b238b8fa9   Chen Gong   pstore: make psto...
545
546
  	*id = part;
  	return ret;
5ee9c198a   Matthew Garrett   efi: Add support ...
547
548
549
550
551
  };
  
  static int efi_pstore_erase(enum pstore_type_id type, u64 id,
  			    struct pstore_info *psi)
  {
3d6d8d20e   Kees Cook   pstore: pass reas...
552
  	efi_pstore_write(type, 0, &id, (unsigned int)id, 0, psi);
5ee9c198a   Matthew Garrett   efi: Add support ...
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  
  	return 0;
  }
  #else
  static int efi_pstore_open(struct pstore_info *psi)
  {
  	return 0;
  }
  
  static int efi_pstore_close(struct pstore_info *psi)
  {
  	return 0;
  }
  
  static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
eee628da2   Christoph Fritz   efivars: add miss...
568
569
  			       struct timespec *timespec,
  			       char **buf, struct pstore_info *psi)
5ee9c198a   Matthew Garrett   efi: Add support ...
570
571
572
  {
  	return -1;
  }
3d6d8d20e   Kees Cook   pstore: pass reas...
573
574
  static int efi_pstore_write(enum pstore_type_id type,
  		enum kmsg_dump_reason reason, u64 *id,
b238b8fa9   Chen Gong   pstore: make psto...
575
  		unsigned int part, size_t size, struct pstore_info *psi)
5ee9c198a   Matthew Garrett   efi: Add support ...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  {
  	return 0;
  }
  
  static int efi_pstore_erase(enum pstore_type_id type, u64 id,
  			    struct pstore_info *psi)
  {
  	return 0;
  }
  #endif
  
  static struct pstore_info efi_pstore_info = {
  	.owner		= THIS_MODULE,
  	.name		= "efi",
  	.open		= efi_pstore_open,
  	.close		= efi_pstore_close,
  	.read		= efi_pstore_read,
  	.write		= efi_pstore_write,
  	.erase		= efi_pstore_erase,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596

2c3c8bea6   Chris Wright   sysfs: add struct...
597
  static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
97fa5bb74   Greg Kroah-Hartman   efivars: make new...
598
599
  			     struct bin_attribute *bin_attr,
  			     char *buf, loff_t pos, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
  {
  	struct efi_variable *new_var = (struct efi_variable *)buf;
4142ef146   Mike Waychison   efivars: paramete...
602
  	struct efivars *efivars = bin_attr->private;
496a0fc8c   Matt Domsch   [PATCH] Fix race ...
603
  	struct efivar_entry *search_efivar, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  	unsigned long strsize1, strsize2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
609
  	efi_status_t status = EFI_NOT_FOUND;
  	int found = 0;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
29422693c   Mike Waychison   efivars: move efi...
610
  	spin_lock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
  
  	/*
  	 * Does this variable already exist?
  	 */
29422693c   Mike Waychison   efivars: move efi...
615
  	list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
a29409083   Mike Waychison   efivars: String f...
616
617
  		strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
  		strsize2 = utf16_strsize(new_var->VariableName, 1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
621
622
623
624
625
626
627
  		if (strsize1 == strsize2 &&
  			!memcmp(&(search_efivar->var.VariableName),
  				new_var->VariableName, strsize1) &&
  			!efi_guidcmp(search_efivar->var.VendorGuid,
  				new_var->VendorGuid)) {
  			found = 1;
  			break;
  		}
  	}
  	if (found) {
29422693c   Mike Waychison   efivars: move efi...
628
  		spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
631
632
  		return -EINVAL;
  	}
  
  	/* now *really* create the variable via EFI */
3295814d8   Mike Waychison   efivars: Paramete...
633
634
635
636
637
  	status = efivars->ops->set_variable(new_var->VariableName,
  					    &new_var->VendorGuid,
  					    new_var->Attributes,
  					    new_var->DataSize,
  					    new_var->Data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
  
  	if (status != EFI_SUCCESS) {
  		printk(KERN_WARNING "efivars: set_variable() failed: status=%lx
  ",
  			status);
29422693c   Mike Waychison   efivars: move efi...
643
  		spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  		return -EIO;
  	}
29422693c   Mike Waychison   efivars: move efi...
646
  	spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  
  	/* Create the entry in sysfs.  Locking is not required here */
4142ef146   Mike Waychison   efivars: paramete...
649
  	status = efivar_create_sysfs_entry(efivars,
a29409083   Mike Waychison   efivars: String f...
650
651
  					   utf16_strsize(new_var->VariableName,
  							 1024),
4142ef146   Mike Waychison   efivars: paramete...
652
653
  					   new_var->VariableName,
  					   &new_var->VendorGuid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
659
  	if (status) {
  		printk(KERN_WARNING "efivars: variable created, but sysfs entry wasn't.
  ");
  	}
  	return count;
  }
2c3c8bea6   Chris Wright   sysfs: add struct...
660
  static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
97fa5bb74   Greg Kroah-Hartman   efivars: make new...
661
662
  			     struct bin_attribute *bin_attr,
  			     char *buf, loff_t pos, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
  {
  	struct efi_variable *del_var = (struct efi_variable *)buf;
4142ef146   Mike Waychison   efivars: paramete...
665
  	struct efivars *efivars = bin_attr->private;
496a0fc8c   Matt Domsch   [PATCH] Fix race ...
666
  	struct efivar_entry *search_efivar, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  	unsigned long strsize1, strsize2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
  	efi_status_t status = EFI_NOT_FOUND;
  	int found = 0;
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
29422693c   Mike Waychison   efivars: move efi...
673
  	spin_lock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
677
  
  	/*
  	 * Does this variable already exist?
  	 */
29422693c   Mike Waychison   efivars: move efi...
678
  	list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
a29409083   Mike Waychison   efivars: String f...
679
680
  		strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
  		strsize2 = utf16_strsize(del_var->VariableName, 1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
685
686
687
688
689
690
  		if (strsize1 == strsize2 &&
  			!memcmp(&(search_efivar->var.VariableName),
  				del_var->VariableName, strsize1) &&
  			!efi_guidcmp(search_efivar->var.VendorGuid,
  				del_var->VendorGuid)) {
  			found = 1;
  			break;
  		}
  	}
  	if (!found) {
29422693c   Mike Waychison   efivars: move efi...
691
  		spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
696
  		return -EINVAL;
  	}
  	/* force the Attributes/DataSize to 0 to ensure deletion */
  	del_var->Attributes = 0;
  	del_var->DataSize = 0;
3295814d8   Mike Waychison   efivars: Paramete...
697
698
699
700
701
  	status = efivars->ops->set_variable(del_var->VariableName,
  					    &del_var->VendorGuid,
  					    del_var->Attributes,
  					    del_var->DataSize,
  					    del_var->Data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
706
  
  	if (status != EFI_SUCCESS) {
  		printk(KERN_WARNING "efivars: set_variable() failed: status=%lx
  ",
  			status);
29422693c   Mike Waychison   efivars: move efi...
707
  		spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
  		return -EIO;
  	}
496a0fc8c   Matt Domsch   [PATCH] Fix race ...
710
  	list_del(&search_efivar->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  	/* We need to release this lock before unregistering. */
29422693c   Mike Waychison   efivars: move efi...
712
  	spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
  	efivar_unregister(search_efivar);
  
  	/* It's dead Jim.... */
  	return count;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
720
721
  /*
   * Let's not leave out systab information that snuck into
   * the efivars driver
   */
334c63075   Greg Kroah-Hartman   kobject: convert ...
722
723
  static ssize_t systab_show(struct kobject *kobj,
  			   struct kobj_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
  {
  	char *str = buf;
334c63075   Greg Kroah-Hartman   kobject: convert ...
726
  	if (!kobj || !buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  		return -EINVAL;
b2c99e3c7   Bjorn Helgaas   [PATCH] EFI: keep...
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
  	if (efi.mps != EFI_INVALID_TABLE_ADDR)
  		str += sprintf(str, "MPS=0x%lx
  ", efi.mps);
  	if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
  		str += sprintf(str, "ACPI20=0x%lx
  ", efi.acpi20);
  	if (efi.acpi != EFI_INVALID_TABLE_ADDR)
  		str += sprintf(str, "ACPI=0x%lx
  ", efi.acpi);
  	if (efi.smbios != EFI_INVALID_TABLE_ADDR)
  		str += sprintf(str, "SMBIOS=0x%lx
  ", efi.smbios);
  	if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
  		str += sprintf(str, "HCDP=0x%lx
  ", efi.hcdp);
  	if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
  		str += sprintf(str, "BOOTINFO=0x%lx
  ", efi.boot_info);
  	if (efi.uga != EFI_INVALID_TABLE_ADDR)
  		str += sprintf(str, "UGA=0x%lx
  ", efi.uga);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
751
  
  	return str - buf;
  }
334c63075   Greg Kroah-Hartman   kobject: convert ...
752
753
  static struct kobj_attribute efi_attr_systab =
  			__ATTR(systab, 0400, systab_show, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754

334c63075   Greg Kroah-Hartman   kobject: convert ...
755
756
  static struct attribute *efi_subsys_attrs[] = {
  	&efi_attr_systab.attr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  	NULL,	/* maybe more in the future? */
  };
334c63075   Greg Kroah-Hartman   kobject: convert ...
759
760
761
  static struct attribute_group efi_subsys_attr_group = {
  	.attrs = efi_subsys_attrs,
  };
bc87d2fe7   Greg Kroah-Hartman   kobject: convert ...
762
  static struct kobject *efi_kobj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
767
768
769
  
  /*
   * efivar_create_sysfs_entry()
   * Requires:
   *    variable_name_size = number of bytes required to hold
   *                         variable_name (not counting the NULL
   *                         character at the end.
29422693c   Mike Waychison   efivars: move efi...
770
   *    efivars->lock is not held on entry or exit.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
   * Returns 1 on failure, 0 on success
   */
  static int
4142ef146   Mike Waychison   efivars: paramete...
774
775
776
777
  efivar_create_sysfs_entry(struct efivars *efivars,
  			  unsigned long variable_name_size,
  			  efi_char16_t *variable_name,
  			  efi_guid_t *vendor_guid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
779
780
781
  {
  	int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
  	char *short_name;
  	struct efivar_entry *new_efivar;
9c2153844   Deepak Saxena   [PATCH] drivers/f...
782
783
  	short_name = kzalloc(short_name_size + 1, GFP_KERNEL);
  	new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
  
  	if (!short_name || !new_efivar)  {
0933ad9c2   Jesper Juhl   [PATCH] kfree cle...
786
787
  		kfree(short_name);
  		kfree(new_efivar);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
  		return 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790

4142ef146   Mike Waychison   efivars: paramete...
791
  	new_efivar->efivars = efivars;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
798
799
800
801
802
803
804
805
  	memcpy(new_efivar->var.VariableName, variable_name,
  		variable_name_size);
  	memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
  
  	/* Convert Unicode to normal chars (assume top bits are 0),
  	   ala UTF-8 */
  	for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
  		short_name[i] = variable_name[i] & 0xFF;
  	}
  	/* This is ugly, but necessary to separate one vendor's
  	   private variables from another's.         */
  
  	*(short_name + strlen(short_name)) = '-';
  	efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
29422693c   Mike Waychison   efivars: move efi...
806
  	new_efivar->kobj.kset = efivars->kset;
d6d292c45   Greg Kroah-Hartman   Kobject: change d...
807
808
  	i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL,
  				 "%s", short_name);
69b2186c5   Jeff Garzik   [PATCH] firmware/...
809
810
811
812
813
  	if (i) {
  		kfree(short_name);
  		kfree(new_efivar);
  		return 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

d6d292c45   Greg Kroah-Hartman   Kobject: change d...
815
  	kobject_uevent(&new_efivar->kobj, KOBJ_ADD);
0933ad9c2   Jesper Juhl   [PATCH] kfree cle...
816
817
  	kfree(short_name);
  	short_name = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818

29422693c   Mike Waychison   efivars: move efi...
819
820
821
  	spin_lock(&efivars->lock);
  	list_add(&new_efivar->list, &efivars->list);
  	spin_unlock(&efivars->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
824
  
  	return 0;
  }
d502fbb0d   Mike Waychison   efivars: Make efi...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
  
  static int
  create_efivars_bin_attributes(struct efivars *efivars)
  {
  	struct bin_attribute *attr;
  	int error;
  
  	/* new_var */
  	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
  	if (!attr)
  		return -ENOMEM;
  
  	attr->attr.name = "new_var";
  	attr->attr.mode = 0200;
  	attr->write = efivar_create;
  	attr->private = efivars;
  	efivars->new_var = attr;
  
  	/* del_var */
  	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
  	if (!attr) {
  		error = -ENOMEM;
  		goto out_free;
  	}
  	attr->attr.name = "del_var";
  	attr->attr.mode = 0200;
  	attr->write = efivar_delete;
  	attr->private = efivars;
  	efivars->del_var = attr;
  
  	sysfs_bin_attr_init(efivars->new_var);
  	sysfs_bin_attr_init(efivars->del_var);
  
  	/* Register */
  	error = sysfs_create_bin_file(&efivars->kset->kobj,
  				      efivars->new_var);
  	if (error) {
  		printk(KERN_ERR "efivars: unable to create new_var sysfs file"
  			" due to error %d
  ", error);
  		goto out_free;
  	}
  	error = sysfs_create_bin_file(&efivars->kset->kobj,
  				      efivars->del_var);
  	if (error) {
  		printk(KERN_ERR "efivars: unable to create del_var sysfs file"
  			" due to error %d
  ", error);
  		sysfs_remove_bin_file(&efivars->kset->kobj,
  				      efivars->new_var);
  		goto out_free;
  	}
  
  	return 0;
  out_free:
051d51bc6   Dan Carpenter   efivars: memory l...
880
881
  	kfree(efivars->del_var);
  	efivars->del_var = NULL;
d502fbb0d   Mike Waychison   efivars: Make efi...
882
883
884
885
  	kfree(efivars->new_var);
  	efivars->new_var = NULL;
  	return error;
  }
4fc756bd9   Mike Waychison   efivars: Expose e...
886
  void unregister_efivars(struct efivars *efivars)
76b53f7c8   Mike Waychison   efivars: Split ou...
887
888
  {
  	struct efivar_entry *entry, *n;
4142ef146   Mike Waychison   efivars: paramete...
889

76b53f7c8   Mike Waychison   efivars: Split ou...
890
891
892
893
894
895
896
897
898
899
900
901
902
903
  	list_for_each_entry_safe(entry, n, &efivars->list, list) {
  		spin_lock(&efivars->lock);
  		list_del(&entry->list);
  		spin_unlock(&efivars->lock);
  		efivar_unregister(entry);
  	}
  	if (efivars->new_var)
  		sysfs_remove_bin_file(&efivars->kset->kobj, efivars->new_var);
  	if (efivars->del_var)
  		sysfs_remove_bin_file(&efivars->kset->kobj, efivars->del_var);
  	kfree(efivars->new_var);
  	kfree(efivars->del_var);
  	kset_unregister(efivars->kset);
  }
4fc756bd9   Mike Waychison   efivars: Expose e...
904
  EXPORT_SYMBOL_GPL(unregister_efivars);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905

4fc756bd9   Mike Waychison   efivars: Expose e...
906
907
908
  int register_efivars(struct efivars *efivars,
  		     const struct efivar_operations *ops,
  		     struct kobject *parent_kobj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
912
  {
  	efi_status_t status = EFI_NOT_FOUND;
  	efi_guid_t vendor_guid;
  	efi_char16_t *variable_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
  	unsigned long variable_name_size = 1024;
334c63075   Greg Kroah-Hartman   kobject: convert ...
914
  	int error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915

9c2153844   Deepak Saxena   [PATCH] drivers/f...
916
  	variable_name = kzalloc(variable_name_size, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
  	if (!variable_name) {
  		printk(KERN_ERR "efivars: Memory allocation failed.
  ");
  		return -ENOMEM;
  	}
29422693c   Mike Waychison   efivars: move efi...
922
923
  	spin_lock_init(&efivars->lock);
  	INIT_LIST_HEAD(&efivars->list);
3295814d8   Mike Waychison   efivars: Paramete...
924
  	efivars->ops = ops;
29422693c   Mike Waychison   efivars: move efi...
925

76b53f7c8   Mike Waychison   efivars: Split ou...
926
  	efivars->kset = kset_create_and_add("vars", NULL, parent_kobj);
29422693c   Mike Waychison   efivars: move efi...
927
  	if (!efivars->kset) {
66ac831e0   Greg Kroah-Hartman   kset: convert efi...
928
929
930
  		printk(KERN_ERR "efivars: Subsystem registration failed.
  ");
  		error = -ENOMEM;
76b53f7c8   Mike Waychison   efivars: Split ou...
931
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
937
938
939
940
  	}
  
  	/*
  	 * Per EFI spec, the maximum storage allocated for both
  	 * the variable name and variable data is 1024 bytes.
  	 */
  
  	do {
  		variable_name_size = 1024;
3295814d8   Mike Waychison   efivars: Paramete...
941
  		status = ops->get_next_variable(&variable_name_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
943
944
945
  						variable_name,
  						&vendor_guid);
  		switch (status) {
  		case EFI_SUCCESS:
4142ef146   Mike Waychison   efivars: paramete...
946
947
948
949
  			efivar_create_sysfs_entry(efivars,
  						  variable_name_size,
  						  variable_name,
  						  &vendor_guid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
954
955
956
957
958
959
960
  			break;
  		case EFI_NOT_FOUND:
  			break;
  		default:
  			printk(KERN_WARNING "efivars: get_next_variable: status=%lx
  ",
  				status);
  			status = EFI_NOT_FOUND;
  			break;
  		}
  	} while (status != EFI_NOT_FOUND);
d502fbb0d   Mike Waychison   efivars: Make efi...
961
  	error = create_efivars_bin_attributes(efivars);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
  	if (error)
76b53f7c8   Mike Waychison   efivars: Split ou...
963
  		unregister_efivars(efivars);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964

5ee9c198a   Matthew Garrett   efi: Add support ...
965
966
967
968
969
970
  	efivars->efi_pstore_info = efi_pstore_info;
  
  	efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
  	if (efivars->efi_pstore_info.buf) {
  		efivars->efi_pstore_info.bufsize = 1024;
  		efivars->efi_pstore_info.data = efivars;
abd4d5587   Don Zickus   pstore: change mu...
971
  		spin_lock_init(&efivars->efi_pstore_info.buf_lock);
5ee9c198a   Matthew Garrett   efi: Add support ...
972
973
  		pstore_register(&efivars->efi_pstore_info);
  	}
76b53f7c8   Mike Waychison   efivars: Split ou...
974
975
  out:
  	kfree(variable_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976

76b53f7c8   Mike Waychison   efivars: Split ou...
977
978
  	return error;
  }
4fc756bd9   Mike Waychison   efivars: Expose e...
979
  EXPORT_SYMBOL_GPL(register_efivars);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980

76b53f7c8   Mike Waychison   efivars: Split ou...
981
  static struct efivars __efivars;
3295814d8   Mike Waychison   efivars: Paramete...
982
  static struct efivar_operations ops;
76b53f7c8   Mike Waychison   efivars: Split ou...
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
  
  /*
   * For now we register the efi subsystem with the firmware subsystem
   * and the vars subsystem with the efi subsystem.  In the future, it
   * might make sense to split off the efi subsystem into its own
   * driver, but for now only efivars will register with it, so just
   * include it here.
   */
  
  static int __init
  efivars_init(void)
  {
  	int error = 0;
  
  	printk(KERN_INFO "EFI Variables Facility v%s %s
  ", EFIVARS_VERSION,
  	       EFIVARS_DATE);
  
  	if (!efi_enabled)
4fc756bd9   Mike Waychison   efivars: Expose e...
1002
  		return 0;
76b53f7c8   Mike Waychison   efivars: Split ou...
1003
1004
1005
1006
1007
1008
1009
1010
  
  	/* For now we'll register the efi directory at /sys/firmware/efi */
  	efi_kobj = kobject_create_and_add("efi", firmware_kobj);
  	if (!efi_kobj) {
  		printk(KERN_ERR "efivars: Firmware registration failed.
  ");
  		return -ENOMEM;
  	}
3295814d8   Mike Waychison   efivars: Paramete...
1011
1012
1013
1014
  	ops.get_variable = efi.get_variable;
  	ops.set_variable = efi.set_variable;
  	ops.get_next_variable = efi.get_next_variable;
  	error = register_efivars(&__efivars, &ops, efi_kobj);
3116aabc8   Dan Carpenter   efivars: handle e...
1015
1016
  	if (error)
  		goto err_put;
76b53f7c8   Mike Waychison   efivars: Split ou...
1017
1018
1019
1020
1021
1022
1023
1024
  
  	/* Don't forget the systab entry */
  	error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
  	if (error) {
  		printk(KERN_ERR
  		       "efivars: Sysfs attribute export failed with error %d.
  ",
  		       error);
3116aabc8   Dan Carpenter   efivars: handle e...
1025
  		goto err_unregister;
76b53f7c8   Mike Waychison   efivars: Split ou...
1026
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027

3116aabc8   Dan Carpenter   efivars: handle e...
1028
1029
1030
1031
1032
1033
  	return 0;
  
  err_unregister:
  	unregister_efivars(&__efivars);
  err_put:
  	kobject_put(efi_kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034
1035
1036
1037
1038
1039
  	return error;
  }
  
  static void __exit
  efivars_exit(void)
  {
aabb6e153   Randy Dunlap   efivars: prevent ...
1040
1041
1042
1043
  	if (efi_enabled) {
  		unregister_efivars(&__efivars);
  		kobject_put(efi_kobj);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
1047
  }
  
  module_init(efivars_init);
  module_exit(efivars_exit);