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#include <linux/config.h>
63#include <linux/types.h>
64#include <linux/errno.h>
65#include <linux/init.h>
66#include <linux/proc_fs.h>
67#include <linux/sched.h>
68#include <linux/mm.h>
69#include <linux/module.h>
70#include <linux/smp.h>
71#include <linux/efi.h>
72
73#include <asm/uaccess.h>
74
75MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
76MODULE_DESCRIPTION("/proc interface to EFI Variables");
77MODULE_LICENSE("GPL");
78
79#define EFIVARS_VERSION "0.06 2002-Dec-10"
80
81static int
82efivar_read(char *page, char **start, off_t off,
83 int count, int *eof, void *data);
84static int
85efivar_write(struct file *file, const char *buffer,
86 unsigned long count, void *data);
87
88
89
90
91
92
93
94
95
96typedef struct _efi_variable_t {
97 efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
98 efi_guid_t VendorGuid;
99 unsigned long DataSize;
100 __u8 Data[1024];
101 efi_status_t Status;
102 __u32 Attributes;
103} __attribute__((packed)) efi_variable_t;
104
105
106typedef struct _efivar_entry_t {
107 efi_variable_t var;
108 struct proc_dir_entry *entry;
109 struct list_head list;
110} efivar_entry_t;
111
112
113
114
115
116
117
118
119
120static spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED;
121static LIST_HEAD(efivar_list);
122static struct proc_dir_entry *efi_vars_dir;
123
124#define efivar_entry(n) list_entry(n, efivar_entry_t, list)
125
126
127static unsigned long
128utf8_strlen(efi_char16_t *data, unsigned long maxlength)
129{
130 unsigned long length = 0;
131 while (*data++ != 0 && length < maxlength)
132 length++;
133 return length;
134}
135
136
137
138static inline unsigned long
139utf8_strsize(efi_char16_t *data, unsigned long maxlength)
140{
141 return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
142}
143
144
145static int
146proc_calc_metrics(char *page, char **start, off_t off,
147 int count, int *eof, int len)
148{
149 if (len <= off+count) *eof = 1;
150 *start = page + off;
151 len -= off;
152 if (len>count) len = count;
153 if (len<0) len = 0;
154 return len;
155}
156
157
158
159
160
161
162
163
164
165
166static int
167efivar_create_proc_entry(unsigned long variable_name_size,
168 efi_char16_t *variable_name,
169 efi_guid_t *vendor_guid)
170{
171 int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
172 char *short_name;
173 efivar_entry_t *new_efivar;
174
175 short_name = kmalloc(short_name_size+1, GFP_KERNEL);
176 new_efivar = kmalloc(sizeof(efivar_entry_t), GFP_KERNEL);
177
178 if (!short_name || !new_efivar) {
179 if (short_name) kfree(short_name);
180 if (new_efivar) kfree(new_efivar);
181 return 1;
182 }
183 memset(short_name, 0, short_name_size+1);
184 memset(new_efivar, 0, sizeof(efivar_entry_t));
185
186 memcpy(new_efivar->var.VariableName, variable_name,
187 variable_name_size);
188 memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
189
190
191
192 for (i=0; i< (int) (variable_name_size / sizeof(efi_char16_t)); i++) {
193 short_name[i] = variable_name[i] & 0xFF;
194 }
195
196
197
198
199 *(short_name + strlen(short_name)) = '-';
200 efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
201
202
203 new_efivar->entry = create_proc_entry(short_name, 0600, efi_vars_dir);
204 kfree(short_name); short_name = NULL;
205 if (!new_efivar->entry) return 1;
206
207 new_efivar->entry->data = new_efivar;
208 new_efivar->entry->read_proc = efivar_read;
209 new_efivar->entry->write_proc = efivar_write;
210
211 spin_lock(&efivars_lock);
212 list_add(&new_efivar->list, &efivar_list);
213 spin_unlock(&efivars_lock);
214
215 return 0;
216}
217
218
219
220
221
222
223
224
225
226
227static int
228efivar_read(char *page, char **start, off_t off, int count, int *eof, void *data)
229{
230 int len = sizeof(efi_variable_t);
231 efivar_entry_t *efi_var = data;
232 efi_variable_t *var_data = (efi_variable_t *)page;
233
234 if (!page || !data) return -EINVAL;
235
236 spin_lock(&efivars_lock);
237 MOD_INC_USE_COUNT;
238
239 memcpy(var_data, &efi_var->var, len);
240
241 var_data->DataSize = 1024;
242 var_data->Status = efi.get_variable(var_data->VariableName,
243 &var_data->VendorGuid,
244 &var_data->Attributes,
245 &var_data->DataSize,
246 var_data->Data);
247
248 MOD_DEC_USE_COUNT;
249 spin_unlock(&efivars_lock);
250
251 return proc_calc_metrics(page, start, off, count, eof, len);
252}
253
254
255
256
257
258
259
260
261
262
263
264static int
265efivar_write(struct file *file, const char *buffer,
266 unsigned long count, void *data)
267{
268 unsigned long strsize1, strsize2;
269 int found=0;
270 struct list_head *pos, *n;
271 unsigned long size = sizeof(efi_variable_t);
272 efi_status_t status;
273 efivar_entry_t *efivar = data, *search_efivar = NULL;
274 efi_variable_t *var_data;
275 if (!data || count != size) {
276 printk(KERN_WARNING "efivars: improper struct of size 0x%lx passed.\n", count);
277 return -EINVAL;
278 }
279 if (!capable(CAP_SYS_ADMIN))
280 return -EACCES;
281
282 MOD_INC_USE_COUNT;
283
284 var_data = kmalloc(size, GFP_KERNEL);
285 if (!var_data) {
286 MOD_DEC_USE_COUNT;
287 return -ENOMEM;
288 }
289 if (copy_from_user(var_data, buffer, size)) {
290 MOD_DEC_USE_COUNT;
291 kfree(var_data);
292 return -EFAULT;
293 }
294
295 spin_lock(&efivars_lock);
296
297
298
299
300
301
302 list_for_each_safe(pos, n, &efivar_list) {
303 search_efivar = efivar_entry(pos);
304 strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
305 strsize2 = utf8_strsize(var_data->VariableName, 1024);
306 if ( strsize1 == strsize2 &&
307 !memcmp(&(search_efivar->var.VariableName),
308 var_data->VariableName, strsize1) &&
309 !efi_guidcmp(search_efivar->var.VendorGuid,
310 var_data->VendorGuid)) {
311 found = 1;
312 break;
313 }
314 }
315 if (found) efivar = search_efivar;
316
317 status = efi.set_variable(var_data->VariableName,
318 &var_data->VendorGuid,
319 var_data->Attributes,
320 var_data->DataSize,
321 var_data->Data);
322
323 if (status != EFI_SUCCESS) {
324 printk(KERN_WARNING "set_variable() failed: status=%lx\n", status);
325 kfree(var_data);
326 MOD_DEC_USE_COUNT;
327 spin_unlock(&efivars_lock);
328 return -EIO;
329 }
330
331
332 if (!var_data->DataSize || !var_data->Attributes) {
333
334 remove_proc_entry(efivar->entry->name, efi_vars_dir);
335 list_del(&efivar->list);
336 kfree(efivar);
337 }
338
339 spin_unlock(&efivars_lock);
340
341
342 if (!found) {
343 efivar_create_proc_entry(utf8_strsize(var_data->VariableName,
344 1024),
345 var_data->VariableName,
346 &var_data->VendorGuid);
347 }
348
349 kfree(var_data);
350 MOD_DEC_USE_COUNT;
351 return size;
352}
353
354
355
356
357
358static ssize_t
359efi_systab_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
360{
361 void *data;
362 u8 *proc_buffer;
363 ssize_t size, length;
364 int ret;
365 const int max_nr_entries = 7;
366 const int max_line_len = 80;
367 loff_t pos = *ppos;
368
369 if (!efi.systab)
370 return 0;
371
372 proc_buffer = kmalloc(max_nr_entries * max_line_len, GFP_KERNEL);
373 if (!proc_buffer)
374 return -ENOMEM;
375
376 length = 0;
377 if (efi.mps)
378 length += sprintf(proc_buffer + length, "MPS=0x%lx\n", __pa(efi.mps));
379 if (efi.acpi20)
380 length += sprintf(proc_buffer + length, "ACPI20=0x%lx\n", __pa(efi.acpi20));
381 if (efi.acpi)
382 length += sprintf(proc_buffer + length, "ACPI=0x%lx\n", __pa(efi.acpi));
383 if (efi.smbios)
384 length += sprintf(proc_buffer + length, "SMBIOS=0x%lx\n", __pa(efi.smbios));
385 if (efi.sal_systab)
386 length += sprintf(proc_buffer + length, "SAL=0x%lx\n", __pa(efi.sal_systab));
387 if (efi.hcdp)
388 length += sprintf(proc_buffer + length, "HCDP=0x%lx\n", __pa(efi.hcdp));
389 if (efi.boot_info)
390 length += sprintf(proc_buffer + length, "BOOTINFO=0x%lx\n", __pa(efi.boot_info));
391
392 if (pos != (unsigned) pos || pos >= length) {
393 ret = 0;
394 goto out;
395 }
396
397 data = proc_buffer + pos;
398 size = length - pos;
399 if (size > count)
400 size = count;
401 if (copy_to_user(buffer, data, size)) {
402 ret = -EFAULT;
403 goto out;
404 }
405
406 *ppos = pos + size;
407 ret = size;
408
409out:
410 kfree(proc_buffer);
411 return ret;
412}
413
414static struct proc_dir_entry *efi_systab_entry;
415static struct file_operations efi_systab_fops = {
416 .read = efi_systab_read,
417};
418
419static int __init
420efivars_init(void)
421{
422 efi_status_t status;
423 efi_guid_t vendor_guid;
424 efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
425 unsigned long variable_name_size = 1024;
426
427 printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION);
428
429
430
431
432
433
434 if (!efi_dir)
435 efi_dir = proc_mkdir("efi", NULL);
436
437 efi_systab_entry = create_proc_entry("systab", S_IRUSR | S_IRGRP, efi_dir);
438 if (efi_systab_entry)
439 efi_systab_entry->proc_fops = &efi_systab_fops;
440
441 efi_vars_dir = proc_mkdir("vars", efi_dir);
442
443
444
445
446
447 memset(variable_name, 0, 1024);
448
449 do {
450 variable_name_size=1024;
451
452 status = efi.get_next_variable(&variable_name_size,
453 variable_name,
454 &vendor_guid);
455
456
457 switch (status) {
458 case EFI_SUCCESS:
459 efivar_create_proc_entry(variable_name_size,
460 variable_name,
461 &vendor_guid);
462 break;
463 case EFI_NOT_FOUND:
464 break;
465 default:
466 printk(KERN_WARNING "get_next_variable: status=%lx\n", status);
467 status = EFI_NOT_FOUND;
468 break;
469 }
470
471 } while (status != EFI_NOT_FOUND);
472
473 kfree(variable_name);
474 return 0;
475}
476
477static void __exit
478efivars_exit(void)
479{
480 struct list_head *pos, *n;
481 efivar_entry_t *efivar;
482
483 spin_lock(&efivars_lock);
484 if (efi_systab_entry)
485 remove_proc_entry(efi_systab_entry->name, efi_dir);
486 list_for_each_safe(pos, n, &efivar_list) {
487 efivar = efivar_entry(pos);
488 remove_proc_entry(efivar->entry->name, efi_vars_dir);
489 list_del(&efivar->list);
490 kfree(efivar);
491 }
492 spin_unlock(&efivars_lock);
493
494 remove_proc_entry(efi_vars_dir->name, efi_dir);
495}
496
497module_init(efivars_init);
498module_exit(efivars_exit);
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518