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