aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Hu <ivan.hu@canonical.com>2016-08-24 23:15:31 -0400
committerMatt Fleming <matt@codeblueprint.co.uk>2016-09-09 11:08:53 -0400
commitff6301dabc3ca20ab8f50f8d0252ac05da610d89 (patch)
tree69e1ff9e859da896eb38de14dbe7e69181cd30a2
parent3dad6f7f6975387f53f1a772f29f54335563d93d (diff)
efi: Add efi_test driver for exporting UEFI runtime service interfaces
This driver is used by the Firmware Test Suite (FWTS) for testing the UEFI runtime interfaces readiness of the firmware. This driver exports UEFI runtime service interfaces into userspace, which allows to use and test UEFI runtime services provided by the firmware. This driver uses the efi.<service> function pointers directly instead of going through the efivar API to allow for direct testing of the UEFI runtime service interfaces provided by the firmware. Details for FWTS are available from, <https://wiki.ubuntu.com/FirmwareTestSuite> Signed-off-by: Ivan Hu <ivan.hu@canonical.com> Cc: joeyli <jlee@suse.com> Cc: Ricardo Neri <ricardo.neri-calderon@linux.intel.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/firmware/efi/Kconfig17
-rw-r--r--drivers/firmware/efi/Makefile1
-rw-r--r--drivers/firmware/efi/test/Makefile1
-rw-r--r--drivers/firmware/efi/test/efi_test.c749
-rw-r--r--drivers/firmware/efi/test/efi_test.h110
6 files changed, 885 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index db814a89599c..007d05acbb5f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4583,6 +4583,13 @@ M: Peter Jones <pjones@redhat.com>
4583S: Maintained 4583S: Maintained
4584F: drivers/video/fbdev/efifb.c 4584F: drivers/video/fbdev/efifb.c
4585 4585
4586EFI TEST DRIVER
4587L: linux-efi@vger.kernel.org
4588M: Ivan Hu <ivan.hu@canonical.com>
4589M: Matt Fleming <matt@codeblueprint.co.uk>
4590S: Maintained
4591F: drivers/firmware/efi/test/
4592
4586EFS FILESYSTEM 4593EFS FILESYSTEM
4587W: http://aeschi.ch.eu.org/efs/ 4594W: http://aeschi.ch.eu.org/efs/
4588S: Orphan 4595S: Orphan
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 6394152f648f..c981be17d3c0 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -112,6 +112,23 @@ config EFI_CAPSULE_LOADER
112 112
113 Most users should say N. 113 Most users should say N.
114 114
115config EFI_TEST
116 tristate "EFI Runtime Service Tests Support"
117 depends on EFI
118 default n
119 help
120 This driver uses the efi.<service> function pointers directly instead
121 of going through the efivar API, because it is not trying to test the
122 kernel subsystem, just for testing the UEFI runtime service
123 interfaces which are provided by the firmware. This driver is used
124 by the Firmware Test Suite (FWTS) for testing the UEFI runtime
125 interfaces readiness of the firmware.
126 Details for FWTS are available from:
127 <https://wiki.ubuntu.com/FirmwareTestSuite>
128
129 Say Y here to enable the runtime services support via /dev/efi_test.
130 If unsure, say N.
131
115endmenu 132endmenu
116 133
117config UEFI_CPER 134config UEFI_CPER
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index b3f5e2adc49f..c8a439f6d715 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
20obj-$(CONFIG_EFI_STUB) += libstub/ 20obj-$(CONFIG_EFI_STUB) += libstub/
21obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o 21obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o
22obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o 22obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
23obj-$(CONFIG_EFI_TEST) += test/
23 24
24arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o 25arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o
25obj-$(CONFIG_ARM) += $(arm-obj-y) 26obj-$(CONFIG_ARM) += $(arm-obj-y)
diff --git a/drivers/firmware/efi/test/Makefile b/drivers/firmware/efi/test/Makefile
new file mode 100644
index 000000000000..bcd4577d40e6
--- /dev/null
+++ b/drivers/firmware/efi/test/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_EFI_TEST) += efi_test.o
diff --git a/drivers/firmware/efi/test/efi_test.c b/drivers/firmware/efi/test/efi_test.c
new file mode 100644
index 000000000000..f61bb52be318
--- /dev/null
+++ b/drivers/firmware/efi/test/efi_test.c
@@ -0,0 +1,749 @@
1/*
2 * EFI Test Driver for Runtime Services
3 *
4 * Copyright(C) 2012-2016 Canonical Ltd.
5 *
6 * This driver exports EFI runtime services interfaces into userspace, which
7 * allow to use and test UEFI runtime services provided by firmware.
8 *
9 */
10
11#include <linux/version.h>
12#include <linux/miscdevice.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/proc_fs.h>
16#include <linux/efi.h>
17#include <linux/slab.h>
18#include <linux/uaccess.h>
19
20#include "efi_test.h"
21
22MODULE_AUTHOR("Ivan Hu <ivan.hu@canonical.com>");
23MODULE_DESCRIPTION("EFI Test Driver");
24MODULE_LICENSE("GPL");
25
26/*
27 * Count the bytes in 'str', including the terminating NULL.
28 *
29 * Note this function returns the number of *bytes*, not the number of
30 * ucs2 characters.
31 */
32static inline size_t user_ucs2_strsize(efi_char16_t __user *str)
33{
34 efi_char16_t *s = str, c;
35 size_t len;
36
37 if (!str)
38 return 0;
39
40 /* Include terminating NULL */
41 len = sizeof(efi_char16_t);
42
43 if (get_user(c, s++)) {
44 /* Can't read userspace memory for size */
45 return 0;
46 }
47
48 while (c != 0) {
49 if (get_user(c, s++)) {
50 /* Can't read userspace memory for size */
51 return 0;
52 }
53 len += sizeof(efi_char16_t);
54 }
55 return len;
56}
57
58/*
59 * Allocate a buffer and copy a ucs2 string from user space into it.
60 */
61static inline int
62copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src,
63 size_t len)
64{
65 efi_char16_t *buf;
66
67 if (!src) {
68 *dst = NULL;
69 return 0;
70 }
71
72 if (!access_ok(VERIFY_READ, src, 1))
73 return -EFAULT;
74
75 buf = kmalloc(len, GFP_KERNEL);
76 if (!buf) {
77 *dst = NULL;
78 return -ENOMEM;
79 }
80 *dst = buf;
81
82 if (copy_from_user(*dst, src, len)) {
83 kfree(buf);
84 return -EFAULT;
85 }
86
87 return 0;
88}
89
90/*
91 * Count the bytes in 'str', including the terminating NULL.
92 *
93 * Just a wrap for user_ucs2_strsize
94 */
95static inline int
96get_ucs2_strsize_from_user(efi_char16_t __user *src, size_t *len)
97{
98 if (!access_ok(VERIFY_READ, src, 1))
99 return -EFAULT;
100
101 *len = user_ucs2_strsize(src);
102 if (*len == 0)
103 return -EFAULT;
104
105 return 0;
106}
107
108/*
109 * Calculate the required buffer allocation size and copy a ucs2 string
110 * from user space into it.
111 *
112 * This function differs from copy_ucs2_from_user_len() because it
113 * calculates the size of the buffer to allocate by taking the length of
114 * the string 'src'.
115 *
116 * If a non-zero value is returned, the caller MUST NOT access 'dst'.
117 *
118 * It is the caller's responsibility to free 'dst'.
119 */
120static inline int
121copy_ucs2_from_user(efi_char16_t **dst, efi_char16_t __user *src)
122{
123 size_t len;
124
125 if (!access_ok(VERIFY_READ, src, 1))
126 return -EFAULT;
127
128 len = user_ucs2_strsize(src);
129 if (len == 0)
130 return -EFAULT;
131 return copy_ucs2_from_user_len(dst, src, len);
132}
133
134/*
135 * Copy a ucs2 string to a user buffer.
136 *
137 * This function is a simple wrapper around copy_to_user() that does
138 * nothing if 'src' is NULL, which is useful for reducing the amount of
139 * NULL checking the caller has to do.
140 *
141 * 'len' specifies the number of bytes to copy.
142 */
143static inline int
144copy_ucs2_to_user_len(efi_char16_t __user *dst, efi_char16_t *src, size_t len)
145{
146 if (!src)
147 return 0;
148
149 if (!access_ok(VERIFY_WRITE, dst, 1))
150 return -EFAULT;
151
152 return copy_to_user(dst, src, len);
153}
154
155static long efi_runtime_get_variable(unsigned long arg)
156{
157 struct efi_getvariable __user *getvariable_user;
158 struct efi_getvariable getvariable;
159 unsigned long datasize, prev_datasize, *dz;
160 efi_guid_t vendor_guid, *vd = NULL;
161 efi_status_t status;
162 efi_char16_t *name = NULL;
163 u32 attr, *at;
164 void *data = NULL;
165 int rv = 0;
166
167 getvariable_user = (struct efi_getvariable __user *)arg;
168
169 if (copy_from_user(&getvariable, getvariable_user,
170 sizeof(getvariable)))
171 return -EFAULT;
172 if (getvariable.data_size &&
173 get_user(datasize, getvariable.data_size))
174 return -EFAULT;
175 if (getvariable.vendor_guid) {
176 if (copy_from_user(&vendor_guid, getvariable.vendor_guid,
177 sizeof(vendor_guid)))
178 return -EFAULT;
179 vd = &vendor_guid;
180 }
181
182 if (getvariable.variable_name) {
183 rv = copy_ucs2_from_user(&name, getvariable.variable_name);
184 if (rv)
185 return rv;
186 }
187
188 at = getvariable.attributes ? &attr : NULL;
189 dz = getvariable.data_size ? &datasize : NULL;
190
191 if (getvariable.data_size && getvariable.data) {
192 data = kmalloc(datasize, GFP_KERNEL);
193 if (!data) {
194 kfree(name);
195 return -ENOMEM;
196 }
197 }
198
199 prev_datasize = datasize;
200 status = efi.get_variable(name, vd, at, dz, data);
201 kfree(name);
202
203 if (put_user(status, getvariable.status)) {
204 rv = -EFAULT;
205 goto out;
206 }
207
208 if (status != EFI_SUCCESS) {
209 if (status == EFI_BUFFER_TOO_SMALL) {
210 if (dz && put_user(datasize, getvariable.data_size)) {
211 rv = -EFAULT;
212 goto out;
213 }
214 }
215 rv = -EINVAL;
216 goto out;
217 }
218
219 if (prev_datasize < datasize) {
220 rv = -EINVAL;
221 goto out;
222 }
223
224 if (data) {
225 if (copy_to_user(getvariable.data, data, datasize)) {
226 rv = -EFAULT;
227 goto out;
228 }
229 }
230
231 if (at && put_user(attr, getvariable.attributes)) {
232 rv = -EFAULT;
233 goto out;
234 }
235
236 if (dz && put_user(datasize, getvariable.data_size))
237 rv = -EFAULT;
238
239out:
240 kfree(data);
241 return rv;
242
243}
244
245static long efi_runtime_set_variable(unsigned long arg)
246{
247 struct efi_setvariable __user *setvariable_user;
248 struct efi_setvariable setvariable;
249 efi_guid_t vendor_guid;
250 efi_status_t status;
251 efi_char16_t *name = NULL;
252 void *data;
253 int rv = 0;
254
255 setvariable_user = (struct efi_setvariable __user *)arg;
256
257 if (copy_from_user(&setvariable, setvariable_user, sizeof(setvariable)))
258 return -EFAULT;
259 if (copy_from_user(&vendor_guid, setvariable.vendor_guid,
260 sizeof(vendor_guid)))
261 return -EFAULT;
262
263 if (setvariable.variable_name) {
264 rv = copy_ucs2_from_user(&name, setvariable.variable_name);
265 if (rv)
266 return rv;
267 }
268
269 data = kmalloc(setvariable.data_size, GFP_KERNEL);
270 if (!data) {
271 kfree(name);
272 return -ENOMEM;
273 }
274 if (copy_from_user(data, setvariable.data, setvariable.data_size)) {
275 rv = -EFAULT;
276 goto out;
277 }
278
279 status = efi.set_variable(name, &vendor_guid,
280 setvariable.attributes,
281 setvariable.data_size, data);
282
283 if (put_user(status, setvariable.status)) {
284 rv = -EFAULT;
285 goto out;
286 }
287
288 rv = status == EFI_SUCCESS ? 0 : -EINVAL;
289
290out:
291 kfree(data);
292 kfree(name);
293
294 return rv;
295}
296
297static long efi_runtime_get_time(unsigned long arg)
298{
299 struct efi_gettime __user *gettime_user;
300 struct efi_gettime gettime;
301 efi_status_t status;
302 efi_time_cap_t cap;
303 efi_time_t efi_time;
304
305 gettime_user = (struct efi_gettime __user *)arg;
306 if (copy_from_user(&gettime, gettime_user, sizeof(gettime)))
307 return -EFAULT;
308
309 status = efi.get_time(gettime.time ? &efi_time : NULL,
310 gettime.capabilities ? &cap : NULL);
311
312 if (put_user(status, gettime.status))
313 return -EFAULT;
314
315 if (status != EFI_SUCCESS)
316 return -EINVAL;
317
318 if (gettime.capabilities) {
319 efi_time_cap_t __user *cap_local;
320
321 cap_local = (efi_time_cap_t *)gettime.capabilities;
322 if (put_user(cap.resolution, &(cap_local->resolution)) ||
323 put_user(cap.accuracy, &(cap_local->accuracy)) ||
324 put_user(cap.sets_to_zero, &(cap_local->sets_to_zero)))
325 return -EFAULT;
326 }
327 if (gettime.time) {
328 if (copy_to_user(gettime.time, &efi_time, sizeof(efi_time_t)))
329 return -EFAULT;
330 }
331
332 return 0;
333}
334
335static long efi_runtime_set_time(unsigned long arg)
336{
337 struct efi_settime __user *settime_user;
338 struct efi_settime settime;
339 efi_status_t status;
340 efi_time_t efi_time;
341
342 settime_user = (struct efi_settime __user *)arg;
343 if (copy_from_user(&settime, settime_user, sizeof(settime)))
344 return -EFAULT;
345 if (copy_from_user(&efi_time, settime.time,
346 sizeof(efi_time_t)))
347 return -EFAULT;
348 status = efi.set_time(&efi_time);
349
350 if (put_user(status, settime.status))
351 return -EFAULT;
352
353 return status == EFI_SUCCESS ? 0 : -EINVAL;
354}
355
356static long efi_runtime_get_waketime(unsigned long arg)
357{
358 struct efi_getwakeuptime __user *getwakeuptime_user;
359 struct efi_getwakeuptime getwakeuptime;
360 efi_bool_t enabled, pending;
361 efi_status_t status;
362 efi_time_t efi_time;
363
364 getwakeuptime_user = (struct efi_getwakeuptime __user *)arg;
365 if (copy_from_user(&getwakeuptime, getwakeuptime_user,
366 sizeof(getwakeuptime)))
367 return -EFAULT;
368
369 status = efi.get_wakeup_time(
370 getwakeuptime.enabled ? (efi_bool_t *)&enabled : NULL,
371 getwakeuptime.pending ? (efi_bool_t *)&pending : NULL,
372 getwakeuptime.time ? &efi_time : NULL);
373
374 if (put_user(status, getwakeuptime.status))
375 return -EFAULT;
376
377 if (status != EFI_SUCCESS)
378 return -EINVAL;
379
380 if (getwakeuptime.enabled && put_user(enabled,
381 getwakeuptime.enabled))
382 return -EFAULT;
383
384 if (getwakeuptime.time) {
385 if (copy_to_user(getwakeuptime.time, &efi_time,
386 sizeof(efi_time_t)))
387 return -EFAULT;
388 }
389
390 return 0;
391}
392
393static long efi_runtime_set_waketime(unsigned long arg)
394{
395 struct efi_setwakeuptime __user *setwakeuptime_user;
396 struct efi_setwakeuptime setwakeuptime;
397 efi_bool_t enabled;
398 efi_status_t status;
399 efi_time_t efi_time;
400
401 setwakeuptime_user = (struct efi_setwakeuptime __user *)arg;
402
403 if (copy_from_user(&setwakeuptime, setwakeuptime_user,
404 sizeof(setwakeuptime)))
405 return -EFAULT;
406
407 enabled = setwakeuptime.enabled;
408 if (setwakeuptime.time) {
409 if (copy_from_user(&efi_time, setwakeuptime.time,
410 sizeof(efi_time_t)))
411 return -EFAULT;
412
413 status = efi.set_wakeup_time(enabled, &efi_time);
414 } else
415 status = efi.set_wakeup_time(enabled, NULL);
416
417 if (put_user(status, setwakeuptime.status))
418 return -EFAULT;
419
420 return status == EFI_SUCCESS ? 0 : -EINVAL;
421}
422
423static long efi_runtime_get_nextvariablename(unsigned long arg)
424{
425 struct efi_getnextvariablename __user *getnextvariablename_user;
426 struct efi_getnextvariablename getnextvariablename;
427 unsigned long name_size, prev_name_size = 0, *ns = NULL;
428 efi_status_t status;
429 efi_guid_t *vd = NULL;
430 efi_guid_t vendor_guid;
431 efi_char16_t *name = NULL;
432 int rv;
433
434 getnextvariablename_user = (struct efi_getnextvariablename __user *)arg;
435
436 if (copy_from_user(&getnextvariablename, getnextvariablename_user,
437 sizeof(getnextvariablename)))
438 return -EFAULT;
439
440 if (getnextvariablename.variable_name_size) {
441 if (get_user(name_size, getnextvariablename.variable_name_size))
442 return -EFAULT;
443 ns = &name_size;
444 prev_name_size = name_size;
445 }
446
447 if (getnextvariablename.vendor_guid) {
448 if (copy_from_user(&vendor_guid,
449 getnextvariablename.vendor_guid,
450 sizeof(vendor_guid)))
451 return -EFAULT;
452 vd = &vendor_guid;
453 }
454
455 if (getnextvariablename.variable_name) {
456 size_t name_string_size = 0;
457
458 rv = get_ucs2_strsize_from_user(
459 getnextvariablename.variable_name,
460 &name_string_size);
461 if (rv)
462 return rv;
463 /*
464 * The name_size may be smaller than the real buffer size where
465 * variable name located in some use cases. The most typical
466 * case is passing a 0 to get the required buffer size for the
467 * 1st time call. So we need to copy the content from user
468 * space for at least the string size of variable name, or else
469 * the name passed to UEFI may not be terminated as we expected.
470 */
471 rv = copy_ucs2_from_user_len(&name,
472 getnextvariablename.variable_name,
473 prev_name_size > name_string_size ?
474 prev_name_size : name_string_size);
475 if (rv)
476 return rv;
477 }
478
479 status = efi.get_next_variable(ns, name, vd);
480
481 if (put_user(status, getnextvariablename.status)) {
482 rv = -EFAULT;
483 goto out;
484 }
485
486 if (status != EFI_SUCCESS) {
487 if (status == EFI_BUFFER_TOO_SMALL) {
488 if (ns && put_user(*ns,
489 getnextvariablename.variable_name_size)) {
490 rv = -EFAULT;
491 goto out;
492 }
493 }
494 rv = -EINVAL;
495 goto out;
496 }
497
498 if (name) {
499 if (copy_ucs2_to_user_len(getnextvariablename.variable_name,
500 name, prev_name_size)) {
501 rv = -EFAULT;
502 goto out;
503 }
504 }
505
506 if (ns) {
507 if (put_user(*ns, getnextvariablename.variable_name_size)) {
508 rv = -EFAULT;
509 goto out;
510 }
511 }
512
513 if (vd) {
514 if (copy_to_user(getnextvariablename.vendor_guid, vd,
515 sizeof(efi_guid_t)))
516 rv = -EFAULT;
517 }
518
519out:
520 kfree(name);
521 return rv;
522}
523
524static long efi_runtime_get_nexthighmonocount(unsigned long arg)
525{
526 struct efi_getnexthighmonotoniccount __user *getnexthighmonocount_user;
527 struct efi_getnexthighmonotoniccount getnexthighmonocount;
528 efi_status_t status;
529 u32 count;
530
531 getnexthighmonocount_user = (struct
532 efi_getnexthighmonotoniccount __user *)arg;
533
534 if (copy_from_user(&getnexthighmonocount,
535 getnexthighmonocount_user,
536 sizeof(getnexthighmonocount)))
537 return -EFAULT;
538
539 status = efi.get_next_high_mono_count(
540 getnexthighmonocount.high_count ? &count : NULL);
541
542 if (put_user(status, getnexthighmonocount.status))
543 return -EFAULT;
544
545 if (status != EFI_SUCCESS)
546 return -EINVAL;
547
548 if (getnexthighmonocount.high_count &&
549 put_user(count, getnexthighmonocount.high_count))
550 return -EFAULT;
551
552 return 0;
553}
554
555static long efi_runtime_query_variableinfo(unsigned long arg)
556{
557 struct efi_queryvariableinfo __user *queryvariableinfo_user;
558 struct efi_queryvariableinfo queryvariableinfo;
559 efi_status_t status;
560 u64 max_storage, remaining, max_size;
561
562 queryvariableinfo_user = (struct efi_queryvariableinfo __user *)arg;
563
564 if (copy_from_user(&queryvariableinfo, queryvariableinfo_user,
565 sizeof(queryvariableinfo)))
566 return -EFAULT;
567
568 status = efi.query_variable_info(queryvariableinfo.attributes,
569 &max_storage, &remaining, &max_size);
570
571 if (put_user(status, queryvariableinfo.status))
572 return -EFAULT;
573
574 if (status != EFI_SUCCESS)
575 return -EINVAL;
576
577 if (put_user(max_storage,
578 queryvariableinfo.maximum_variable_storage_size))
579 return -EFAULT;
580
581 if (put_user(remaining,
582 queryvariableinfo.remaining_variable_storage_size))
583 return -EFAULT;
584
585 if (put_user(max_size, queryvariableinfo.maximum_variable_size))
586 return -EFAULT;
587
588 return 0;
589}
590
591static long efi_runtime_query_capsulecaps(unsigned long arg)
592{
593 struct efi_querycapsulecapabilities __user *qcaps_user;
594 struct efi_querycapsulecapabilities qcaps;
595 efi_capsule_header_t *capsules;
596 efi_status_t status;
597 u64 max_size;
598 int i, reset_type;
599 int rv = 0;
600
601 qcaps_user = (struct efi_querycapsulecapabilities __user *)arg;
602
603 if (copy_from_user(&qcaps, qcaps_user, sizeof(qcaps)))
604 return -EFAULT;
605
606 capsules = kcalloc(qcaps.capsule_count + 1,
607 sizeof(efi_capsule_header_t), GFP_KERNEL);
608 if (!capsules)
609 return -ENOMEM;
610
611 for (i = 0; i < qcaps.capsule_count; i++) {
612 efi_capsule_header_t *c;
613 /*
614 * We cannot dereference qcaps.capsule_header_array directly to
615 * obtain the address of the capsule as it resides in the
616 * user space
617 */
618 if (get_user(c, qcaps.capsule_header_array + i)) {
619 rv = -EFAULT;
620 goto out;
621 }
622 if (copy_from_user(&capsules[i], c,
623 sizeof(efi_capsule_header_t))) {
624 rv = -EFAULT;
625 goto out;
626 }
627 }
628
629 qcaps.capsule_header_array = &capsules;
630
631 status = efi.query_capsule_caps((efi_capsule_header_t **)
632 qcaps.capsule_header_array,
633 qcaps.capsule_count,
634 &max_size, &reset_type);
635
636 if (put_user(status, qcaps.status)) {
637 rv = -EFAULT;
638 goto out;
639 }
640
641 if (status != EFI_SUCCESS) {
642 rv = -EINVAL;
643 goto out;
644 }
645
646 if (put_user(max_size, qcaps.maximum_capsule_size)) {
647 rv = -EFAULT;
648 goto out;
649 }
650
651 if (put_user(reset_type, qcaps.reset_type))
652 rv = -EFAULT;
653
654out:
655 kfree(capsules);
656 return rv;
657}
658
659static long efi_test_ioctl(struct file *file, unsigned int cmd,
660 unsigned long arg)
661{
662 switch (cmd) {
663 case EFI_RUNTIME_GET_VARIABLE:
664 return efi_runtime_get_variable(arg);
665
666 case EFI_RUNTIME_SET_VARIABLE:
667 return efi_runtime_set_variable(arg);
668
669 case EFI_RUNTIME_GET_TIME:
670 return efi_runtime_get_time(arg);
671
672 case EFI_RUNTIME_SET_TIME:
673 return efi_runtime_set_time(arg);
674
675 case EFI_RUNTIME_GET_WAKETIME:
676 return efi_runtime_get_waketime(arg);
677
678 case EFI_RUNTIME_SET_WAKETIME:
679 return efi_runtime_set_waketime(arg);
680
681 case EFI_RUNTIME_GET_NEXTVARIABLENAME:
682 return efi_runtime_get_nextvariablename(arg);
683
684 case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT:
685 return efi_runtime_get_nexthighmonocount(arg);
686
687 case EFI_RUNTIME_QUERY_VARIABLEINFO:
688 return efi_runtime_query_variableinfo(arg);
689
690 case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES:
691 return efi_runtime_query_capsulecaps(arg);
692 }
693
694 return -ENOTTY;
695}
696
697static int efi_test_open(struct inode *inode, struct file *file)
698{
699 /*
700 * nothing special to do here
701 * We do accept multiple open files at the same time as we
702 * synchronize on the per call operation.
703 */
704 return 0;
705}
706
707static int efi_test_close(struct inode *inode, struct file *file)
708{
709 return 0;
710}
711
712/*
713 * The various file operations we support.
714 */
715static const struct file_operations efi_test_fops = {
716 .owner = THIS_MODULE,
717 .unlocked_ioctl = efi_test_ioctl,
718 .open = efi_test_open,
719 .release = efi_test_close,
720 .llseek = no_llseek,
721};
722
723static struct miscdevice efi_test_dev = {
724 MISC_DYNAMIC_MINOR,
725 "efi_test",
726 &efi_test_fops
727};
728
729static int __init efi_test_init(void)
730{
731 int ret;
732
733 ret = misc_register(&efi_test_dev);
734 if (ret) {
735 pr_err("efi_test: can't misc_register on minor=%d\n",
736 MISC_DYNAMIC_MINOR);
737 return ret;
738 }
739
740 return 0;
741}
742
743static void __exit efi_test_exit(void)
744{
745 misc_deregister(&efi_test_dev);
746}
747
748module_init(efi_test_init);
749module_exit(efi_test_exit);
diff --git a/drivers/firmware/efi/test/efi_test.h b/drivers/firmware/efi/test/efi_test.h
new file mode 100644
index 000000000000..a33a6c633852
--- /dev/null
+++ b/drivers/firmware/efi/test/efi_test.h
@@ -0,0 +1,110 @@
1/*
2 * EFI Test driver Header
3 *
4 * Copyright(C) 2012-2016 Canonical Ltd.
5 *
6 */
7
8#ifndef _DRIVERS_FIRMWARE_EFI_TEST_H_
9#define _DRIVERS_FIRMWARE_EFI_TEST_H_
10
11#include <linux/efi.h>
12
13struct efi_getvariable {
14 efi_char16_t *variable_name;
15 efi_guid_t *vendor_guid;
16 u32 *attributes;
17 unsigned long *data_size;
18 void *data;
19 efi_status_t *status;
20} __packed;
21
22struct efi_setvariable {
23 efi_char16_t *variable_name;
24 efi_guid_t *vendor_guid;
25 u32 attributes;
26 unsigned long data_size;
27 void *data;
28 efi_status_t *status;
29} __packed;
30
31struct efi_getnextvariablename {
32 unsigned long *variable_name_size;
33 efi_char16_t *variable_name;
34 efi_guid_t *vendor_guid;
35 efi_status_t *status;
36} __packed;
37
38struct efi_queryvariableinfo {
39 u32 attributes;
40 u64 *maximum_variable_storage_size;
41 u64 *remaining_variable_storage_size;
42 u64 *maximum_variable_size;
43 efi_status_t *status;
44} __packed;
45
46struct efi_gettime {
47 efi_time_t *time;
48 efi_time_cap_t *capabilities;
49 efi_status_t *status;
50} __packed;
51
52struct efi_settime {
53 efi_time_t *time;
54 efi_status_t *status;
55} __packed;
56
57struct efi_getwakeuptime {
58 efi_bool_t *enabled;
59 efi_bool_t *pending;
60 efi_time_t *time;
61 efi_status_t *status;
62} __packed;
63
64struct efi_setwakeuptime {
65 efi_bool_t enabled;
66 efi_time_t *time;
67 efi_status_t *status;
68} __packed;
69
70struct efi_getnexthighmonotoniccount {
71 u32 *high_count;
72 efi_status_t *status;
73} __packed;
74
75struct efi_querycapsulecapabilities {
76 efi_capsule_header_t **capsule_header_array;
77 unsigned long capsule_count;
78 u64 *maximum_capsule_size;
79 int *reset_type;
80 efi_status_t *status;
81} __packed;
82
83#define EFI_RUNTIME_GET_VARIABLE \
84 _IOWR('p', 0x01, struct efi_getvariable)
85#define EFI_RUNTIME_SET_VARIABLE \
86 _IOW('p', 0x02, struct efi_setvariable)
87
88#define EFI_RUNTIME_GET_TIME \
89 _IOR('p', 0x03, struct efi_gettime)
90#define EFI_RUNTIME_SET_TIME \
91 _IOW('p', 0x04, struct efi_settime)
92
93#define EFI_RUNTIME_GET_WAKETIME \
94 _IOR('p', 0x05, struct efi_getwakeuptime)
95#define EFI_RUNTIME_SET_WAKETIME \
96 _IOW('p', 0x06, struct efi_setwakeuptime)
97
98#define EFI_RUNTIME_GET_NEXTVARIABLENAME \
99 _IOWR('p', 0x07, struct efi_getnextvariablename)
100
101#define EFI_RUNTIME_QUERY_VARIABLEINFO \
102 _IOR('p', 0x08, struct efi_queryvariableinfo)
103
104#define EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT \
105 _IOR('p', 0x09, struct efi_getnexthighmonotoniccount)
106
107#define EFI_RUNTIME_QUERY_CAPSULECAPABILITIES \
108 _IOR('p', 0x0A, struct efi_querycapsulecapabilities)
109
110#endif /* _DRIVERS_FIRMWARE_EFI_TEST_H_ */