cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

efi_test.c (17791B)


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