linux/drivers/firmware/efi/test/efi_test.c
<<
>>
Prefs
   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);
 783