The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/efidev/efirt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2004 Marcel Moolenaar
    3  * Copyright (c) 2001 Doug Rabson
    4  * Copyright (c) 2016, 2018 The FreeBSD Foundation
    5  * All rights reserved.
    6  *
    7  * Portions of this software were developed by Konstantin Belousov
    8  * under sponsorship from the FreeBSD Foundation.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <sys/param.h>
   36 #include <sys/efi.h>
   37 #include <sys/eventhandler.h>
   38 #include <sys/kernel.h>
   39 #include <sys/linker.h>
   40 #include <sys/lock.h>
   41 #include <sys/malloc.h>
   42 #include <sys/module.h>
   43 #include <sys/msan.h>
   44 #include <sys/mutex.h>
   45 #include <sys/clock.h>
   46 #include <sys/proc.h>
   47 #include <sys/reboot.h>
   48 #include <sys/rwlock.h>
   49 #include <sys/sched.h>
   50 #include <sys/sysctl.h>
   51 #include <sys/systm.h>
   52 #include <sys/uio.h>
   53 #include <sys/vmmeter.h>
   54 
   55 #include <machine/fpu.h>
   56 #include <machine/efi.h>
   57 #include <machine/metadata.h>
   58 #include <machine/vmparam.h>
   59 
   60 #include <vm/vm.h>
   61 #include <vm/pmap.h>
   62 #include <vm/vm_map.h>
   63 
   64 #define EFI_TABLE_ALLOC_MAX 0x800000
   65 
   66 static struct efi_systbl *efi_systbl;
   67 static eventhandler_tag efi_shutdown_tag;
   68 /*
   69  * The following pointers point to tables in the EFI runtime service data pages.
   70  * Care should be taken to make sure that we've properly entered the EFI runtime
   71  * environment (efi_enter()) before dereferencing them.
   72  */
   73 static struct efi_cfgtbl *efi_cfgtbl;
   74 static struct efi_rt *efi_runtime;
   75 
   76 static int efi_status2err[25] = {
   77         0,              /* EFI_SUCCESS */
   78         ENOEXEC,        /* EFI_LOAD_ERROR */
   79         EINVAL,         /* EFI_INVALID_PARAMETER */
   80         ENOSYS,         /* EFI_UNSUPPORTED */
   81         EMSGSIZE,       /* EFI_BAD_BUFFER_SIZE */
   82         EOVERFLOW,      /* EFI_BUFFER_TOO_SMALL */
   83         EBUSY,          /* EFI_NOT_READY */
   84         EIO,            /* EFI_DEVICE_ERROR */
   85         EROFS,          /* EFI_WRITE_PROTECTED */
   86         EAGAIN,         /* EFI_OUT_OF_RESOURCES */
   87         EIO,            /* EFI_VOLUME_CORRUPTED */
   88         ENOSPC,         /* EFI_VOLUME_FULL */
   89         ENXIO,          /* EFI_NO_MEDIA */
   90         ESTALE,         /* EFI_MEDIA_CHANGED */
   91         ENOENT,         /* EFI_NOT_FOUND */
   92         EACCES,         /* EFI_ACCESS_DENIED */
   93         ETIMEDOUT,      /* EFI_NO_RESPONSE */
   94         EADDRNOTAVAIL,  /* EFI_NO_MAPPING */
   95         ETIMEDOUT,      /* EFI_TIMEOUT */
   96         EDOOFUS,        /* EFI_NOT_STARTED */
   97         EALREADY,       /* EFI_ALREADY_STARTED */
   98         ECANCELED,      /* EFI_ABORTED */
   99         EPROTO,         /* EFI_ICMP_ERROR */
  100         EPROTO,         /* EFI_TFTP_ERROR */
  101         EPROTO          /* EFI_PROTOCOL_ERROR */
  102 };
  103 
  104 enum efi_table_type {
  105         TYPE_ESRT = 0,
  106         TYPE_PROP
  107 };
  108 
  109 static int efi_enter(void);
  110 static void efi_leave(void);
  111 
  112 int
  113 efi_status_to_errno(efi_status status)
  114 {
  115         u_long code;
  116 
  117         code = status & 0x3ffffffffffffffful;
  118         return (code < nitems(efi_status2err) ? efi_status2err[code] : EDOOFUS);
  119 }
  120 
  121 static struct mtx efi_lock;
  122 static SYSCTL_NODE(_hw, OID_AUTO, efi, CTLFLAG_RWTUN | CTLFLAG_MPSAFE, NULL,
  123     "EFI");
  124 static bool efi_poweroff = true;
  125 SYSCTL_BOOL(_hw_efi, OID_AUTO, poweroff, CTLFLAG_RWTUN, &efi_poweroff, 0,
  126     "If true, use EFI runtime services to power off in preference to ACPI");
  127 
  128 static bool
  129 efi_is_in_map(struct efi_md *map, int ndesc, int descsz, vm_offset_t addr)
  130 {
  131         struct efi_md *p;
  132         int i;
  133 
  134         for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p,
  135             descsz)) {
  136                 if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
  137                         continue;
  138 
  139                 if (addr >= p->md_virt &&
  140                     addr < p->md_virt + p->md_pages * EFI_PAGE_SIZE)
  141                         return (true);
  142         }
  143 
  144         return (false);
  145 }
  146 
  147 static void
  148 efi_shutdown_final(void *dummy __unused, int howto)
  149 {
  150 
  151         /*
  152          * On some systems, ACPI S5 is missing or does not function properly.
  153          * When present, shutdown via EFI Runtime Services instead, unless
  154          * disabled.
  155          */
  156         if ((howto & RB_POWEROFF) != 0 && efi_poweroff)
  157                 (void)efi_reset_system(EFI_RESET_SHUTDOWN);
  158 }
  159 
  160 static int
  161 efi_init(void)
  162 {
  163         struct efi_map_header *efihdr;
  164         struct efi_md *map;
  165         struct efi_rt *rtdm;
  166         caddr_t kmdp;
  167         size_t efisz;
  168         int ndesc, rt_disabled;
  169 
  170         rt_disabled = 0;
  171         TUNABLE_INT_FETCH("efi.rt.disabled", &rt_disabled);
  172         if (rt_disabled == 1)
  173                 return (0);
  174         mtx_init(&efi_lock, "efi", NULL, MTX_DEF);
  175 
  176         if (efi_systbl_phys == 0) {
  177                 if (bootverbose)
  178                         printf("EFI systbl not available\n");
  179                 return (0);
  180         }
  181 
  182         efi_systbl = (struct efi_systbl *)efi_phys_to_kva(efi_systbl_phys);
  183         if (efi_systbl == NULL || efi_systbl->st_hdr.th_sig != EFI_SYSTBL_SIG) {
  184                 efi_systbl = NULL;
  185                 if (bootverbose)
  186                         printf("EFI systbl signature invalid\n");
  187                 return (0);
  188         }
  189         efi_cfgtbl = (efi_systbl->st_cfgtbl == 0) ? NULL :
  190             (struct efi_cfgtbl *)efi_systbl->st_cfgtbl;
  191         if (efi_cfgtbl == NULL) {
  192                 if (bootverbose)
  193                         printf("EFI config table is not present\n");
  194         }
  195 
  196         kmdp = preload_search_by_type("elf kernel");
  197         if (kmdp == NULL)
  198                 kmdp = preload_search_by_type("elf64 kernel");
  199         efihdr = (struct efi_map_header *)preload_search_info(kmdp,
  200             MODINFO_METADATA | MODINFOMD_EFI_MAP);
  201         if (efihdr == NULL) {
  202                 if (bootverbose)
  203                         printf("EFI map is not present\n");
  204                 return (0);
  205         }
  206         efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
  207         map = (struct efi_md *)((uint8_t *)efihdr + efisz);
  208         if (efihdr->descriptor_size == 0)
  209                 return (ENOMEM);
  210 
  211         ndesc = efihdr->memory_size / efihdr->descriptor_size;
  212         if (!efi_create_1t1_map(map, ndesc, efihdr->descriptor_size)) {
  213                 if (bootverbose)
  214                         printf("EFI cannot create runtime map\n");
  215                 return (ENOMEM);
  216         }
  217 
  218         efi_runtime = (efi_systbl->st_rt == 0) ? NULL :
  219             (struct efi_rt *)efi_systbl->st_rt;
  220         if (efi_runtime == NULL) {
  221                 if (bootverbose)
  222                         printf("EFI runtime services table is not present\n");
  223                 efi_destroy_1t1_map();
  224                 return (ENXIO);
  225         }
  226 
  227 #if defined(__aarch64__) || defined(__amd64__)
  228         /*
  229          * Some UEFI implementations have multiple implementations of the
  230          * RS->GetTime function. They switch from one we can only use early
  231          * in the boot process to one valid as a RunTime service only when we
  232          * call RS->SetVirtualAddressMap. As this is not always the case, e.g.
  233          * with an old loader.efi, check if the RS->GetTime function is within
  234          * the EFI map, and fail to attach if not.
  235          */
  236         rtdm = (struct efi_rt *)efi_phys_to_kva((uintptr_t)efi_runtime);
  237         if (rtdm == NULL || !efi_is_in_map(map, ndesc, efihdr->descriptor_size,
  238             (vm_offset_t)rtdm->rt_gettime)) {
  239                 if (bootverbose)
  240                         printf(
  241                          "EFI runtime services table has an invalid pointer\n");
  242                 efi_runtime = NULL;
  243                 efi_destroy_1t1_map();
  244                 return (ENXIO);
  245         }
  246 #endif
  247 
  248         /*
  249          * We use SHUTDOWN_PRI_LAST - 1 to trigger after IPMI, but before ACPI.
  250          */
  251         efi_shutdown_tag = EVENTHANDLER_REGISTER(shutdown_final,
  252             efi_shutdown_final, NULL, SHUTDOWN_PRI_LAST - 1);
  253 
  254         return (0);
  255 }
  256 
  257 static void
  258 efi_uninit(void)
  259 {
  260 
  261         /* Most likely disabled by tunable */
  262         if (efi_runtime == NULL)
  263                 return;
  264         if (efi_shutdown_tag != NULL)
  265                 EVENTHANDLER_DEREGISTER(shutdown_final, efi_shutdown_tag);
  266         efi_destroy_1t1_map();
  267 
  268         efi_systbl = NULL;
  269         efi_cfgtbl = NULL;
  270         efi_runtime = NULL;
  271 
  272         mtx_destroy(&efi_lock);
  273 }
  274 
  275 static int
  276 rt_ok(void)
  277 {
  278 
  279         if (efi_runtime == NULL)
  280                 return (ENXIO);
  281         return (0);
  282 }
  283 
  284 static int
  285 efi_enter(void)
  286 {
  287         struct thread *td;
  288         pmap_t curpmap;
  289         int error;
  290 
  291         if (efi_runtime == NULL)
  292                 return (ENXIO);
  293         td = curthread;
  294         curpmap = &td->td_proc->p_vmspace->vm_pmap;
  295         PMAP_LOCK(curpmap);
  296         mtx_lock(&efi_lock);
  297         fpu_kern_enter(td, NULL, FPU_KERN_NOCTX);
  298         error = efi_arch_enter();
  299         if (error != 0) {
  300                 fpu_kern_leave(td, NULL);
  301                 mtx_unlock(&efi_lock);
  302                 PMAP_UNLOCK(curpmap);
  303         }
  304         return (error);
  305 }
  306 
  307 static void
  308 efi_leave(void)
  309 {
  310         struct thread *td;
  311         pmap_t curpmap;
  312 
  313         efi_arch_leave();
  314 
  315         curpmap = &curproc->p_vmspace->vm_pmap;
  316         td = curthread;
  317         fpu_kern_leave(td, NULL);
  318         mtx_unlock(&efi_lock);
  319         PMAP_UNLOCK(curpmap);
  320 }
  321 
  322 static int
  323 get_table(struct uuid *uuid, void **ptr)
  324 {
  325         struct efi_cfgtbl *ct;
  326         u_long count;
  327         int error;
  328 
  329         if (efi_cfgtbl == NULL || efi_systbl == NULL)
  330                 return (ENXIO);
  331         error = efi_enter();
  332         if (error != 0)
  333                 return (error);
  334         count = efi_systbl->st_entries;
  335         ct = efi_cfgtbl;
  336         while (count--) {
  337                 if (!bcmp(&ct->ct_uuid, uuid, sizeof(*uuid))) {
  338                         *ptr = ct->ct_data;
  339                         efi_leave();
  340                         return (0);
  341                 }
  342                 ct++;
  343         }
  344 
  345         efi_leave();
  346         return (ENOENT);
  347 }
  348 
  349 static int
  350 get_table_length(enum efi_table_type type, size_t *table_len, void **taddr)
  351 {
  352         switch (type) {
  353         case TYPE_ESRT:
  354         {
  355                 struct efi_esrt_table *esrt = NULL;
  356                 struct uuid uuid = EFI_TABLE_ESRT;
  357                 uint32_t fw_resource_count = 0;
  358                 size_t len = sizeof(*esrt);
  359                 int error;
  360                 void *buf;
  361 
  362                 error = efi_get_table(&uuid, (void **)&esrt);
  363                 if (error != 0)
  364                         return (error);
  365 
  366                 buf = malloc(len, M_TEMP, M_WAITOK);
  367                 error = physcopyout((vm_paddr_t)esrt, buf, len);
  368                 if (error != 0) {
  369                         free(buf, M_TEMP);
  370                         return (error);
  371                 }
  372 
  373                 /* Check ESRT version */
  374                 if (((struct efi_esrt_table *)buf)->fw_resource_version !=
  375                     ESRT_FIRMWARE_RESOURCE_VERSION) {
  376                         free(buf, M_TEMP);
  377                         return (ENODEV);
  378                 }
  379 
  380                 fw_resource_count = ((struct efi_esrt_table *)buf)->
  381                     fw_resource_count;
  382                 if (fw_resource_count > EFI_TABLE_ALLOC_MAX /
  383                     sizeof(struct efi_esrt_entry_v1)) {
  384                         free(buf, M_TEMP);
  385                         return (ENOMEM);
  386                 }
  387 
  388                 len += fw_resource_count * sizeof(struct efi_esrt_entry_v1);
  389                 *table_len = len;
  390 
  391                 if (taddr != NULL)
  392                         *taddr = esrt;
  393                 free(buf, M_TEMP);
  394                 return (0);
  395         }
  396         case TYPE_PROP:
  397         {
  398                 struct uuid uuid = EFI_PROPERTIES_TABLE;
  399                 struct efi_prop_table *prop;
  400                 size_t len = sizeof(*prop);
  401                 uint32_t prop_len;
  402                 int error;
  403                 void *buf;
  404 
  405                 error = efi_get_table(&uuid, (void **)&prop);
  406                 if (error != 0)
  407                         return (error);
  408 
  409                 buf = malloc(len, M_TEMP, M_WAITOK);
  410                 error = physcopyout((vm_paddr_t)prop, buf, len);
  411                 if (error != 0) {
  412                         free(buf, M_TEMP);
  413                         return (error);
  414                 }
  415 
  416                 prop_len = ((struct efi_prop_table *)buf)->length;
  417                 if (prop_len > EFI_TABLE_ALLOC_MAX) {
  418                         free(buf, M_TEMP);
  419                         return (ENOMEM);
  420                 }
  421                 *table_len = prop_len;
  422 
  423                 if (taddr != NULL)
  424                         *taddr = prop;
  425                 free(buf, M_TEMP);
  426                 return (0);
  427         }
  428         }
  429         return (ENOENT);
  430 }
  431 
  432 static int
  433 copy_table(struct uuid *uuid, void **buf, size_t buf_len, size_t *table_len)
  434 {
  435         static const struct known_table {
  436                 struct uuid uuid;
  437                 enum efi_table_type type;
  438         } tables[] = {
  439                 { EFI_TABLE_ESRT,       TYPE_ESRT },
  440                 { EFI_PROPERTIES_TABLE, TYPE_PROP }
  441         };
  442         size_t table_idx;
  443         void *taddr;
  444         int rc;
  445 
  446         for (table_idx = 0; table_idx < nitems(tables); table_idx++) {
  447                 if (!bcmp(&tables[table_idx].uuid, uuid, sizeof(*uuid)))
  448                         break;
  449         }
  450 
  451         if (table_idx == nitems(tables))
  452                 return (EINVAL);
  453 
  454         rc = get_table_length(tables[table_idx].type, table_len, &taddr);
  455         if (rc != 0)
  456                 return rc;
  457 
  458         /* return table length to userspace */
  459         if (buf == NULL)
  460                 return (0);
  461 
  462         *buf = malloc(*table_len, M_TEMP, M_WAITOK);
  463         rc = physcopyout((vm_paddr_t)taddr, *buf, *table_len);
  464         return (rc);
  465 }
  466 
  467 static int efi_rt_handle_faults = EFI_RT_HANDLE_FAULTS_DEFAULT;
  468 SYSCTL_INT(_machdep, OID_AUTO, efi_rt_handle_faults, CTLFLAG_RWTUN,
  469     &efi_rt_handle_faults, 0,
  470     "Call EFI RT methods with fault handler wrapper around");
  471 
  472 static int
  473 efi_rt_arch_call_nofault(struct efirt_callinfo *ec)
  474 {
  475 
  476         switch (ec->ec_argcnt) {
  477         case 0:
  478                 ec->ec_efi_status = ((register_t (*)(void))ec->ec_fptr)();
  479                 break;
  480         case 1:
  481                 ec->ec_efi_status = ((register_t (*)(register_t))ec->ec_fptr)
  482                     (ec->ec_arg1);
  483                 break;
  484         case 2:
  485                 ec->ec_efi_status = ((register_t (*)(register_t, register_t))
  486                     ec->ec_fptr)(ec->ec_arg1, ec->ec_arg2);
  487                 break;
  488         case 3:
  489                 ec->ec_efi_status = ((register_t (*)(register_t, register_t,
  490                     register_t))ec->ec_fptr)(ec->ec_arg1, ec->ec_arg2,
  491                     ec->ec_arg3);
  492                 break;
  493         case 4:
  494                 ec->ec_efi_status = ((register_t (*)(register_t, register_t,
  495                     register_t, register_t))ec->ec_fptr)(ec->ec_arg1,
  496                     ec->ec_arg2, ec->ec_arg3, ec->ec_arg4);
  497                 break;
  498         case 5:
  499                 ec->ec_efi_status = ((register_t (*)(register_t, register_t,
  500                     register_t, register_t, register_t))ec->ec_fptr)(
  501                     ec->ec_arg1, ec->ec_arg2, ec->ec_arg3, ec->ec_arg4,
  502                     ec->ec_arg5);
  503                 break;
  504         default:
  505                 panic("efi_rt_arch_call: %d args", (int)ec->ec_argcnt);
  506         }
  507 
  508         return (0);
  509 }
  510 
  511 static int
  512 efi_call(struct efirt_callinfo *ecp)
  513 {
  514         int error;
  515 
  516         error = efi_enter();
  517         if (error != 0)
  518                 return (error);
  519         error = efi_rt_handle_faults ? efi_rt_arch_call(ecp) :
  520             efi_rt_arch_call_nofault(ecp);
  521         efi_leave();
  522         if (error == 0)
  523                 error = efi_status_to_errno(ecp->ec_efi_status);
  524         else if (bootverbose)
  525                 printf("EFI %s call faulted, error %d\n", ecp->ec_name, error);
  526         return (error);
  527 }
  528 
  529 #define EFI_RT_METHOD_PA(method)                                \
  530     ((uintptr_t)((struct efi_rt *)efi_phys_to_kva((uintptr_t)   \
  531     efi_runtime))->method)
  532 
  533 static int
  534 efi_get_time_locked(struct efi_tm *tm, struct efi_tmcap *tmcap)
  535 {
  536         struct efirt_callinfo ec;
  537         int error;
  538 
  539         EFI_TIME_OWNED();
  540         if (efi_runtime == NULL)
  541                 return (ENXIO);
  542         bzero(&ec, sizeof(ec));
  543         ec.ec_name = "rt_gettime";
  544         ec.ec_argcnt = 2;
  545         ec.ec_arg1 = (uintptr_t)tm;
  546         ec.ec_arg2 = (uintptr_t)tmcap;
  547         ec.ec_fptr = EFI_RT_METHOD_PA(rt_gettime);
  548         error = efi_call(&ec);
  549         if (error == 0)
  550                 kmsan_mark(tm, sizeof(*tm), KMSAN_STATE_INITED);
  551         return (error);
  552 }
  553 
  554 static int
  555 get_time(struct efi_tm *tm)
  556 {
  557         struct efi_tmcap dummy;
  558         int error;
  559 
  560         if (efi_runtime == NULL)
  561                 return (ENXIO);
  562         EFI_TIME_LOCK();
  563         /*
  564          * UEFI spec states that the Capabilities argument to GetTime is
  565          * optional, but some UEFI implementations choke when passed a NULL
  566          * pointer. Pass a dummy efi_tmcap, even though we won't use it,
  567          * to workaround such implementations.
  568          */
  569         error = efi_get_time_locked(tm, &dummy);
  570         EFI_TIME_UNLOCK();
  571         return (error);
  572 }
  573 
  574 static int
  575 get_time_capabilities(struct efi_tmcap *tmcap)
  576 {
  577         struct efi_tm dummy;
  578         int error;
  579 
  580         if (efi_runtime == NULL)
  581                 return (ENXIO);
  582         EFI_TIME_LOCK();
  583         error = efi_get_time_locked(&dummy, tmcap);
  584         EFI_TIME_UNLOCK();
  585         return (error);
  586 }
  587 
  588 static int
  589 reset_system(enum efi_reset type)
  590 {
  591         struct efirt_callinfo ec;
  592 
  593         switch (type) {
  594         case EFI_RESET_COLD:
  595         case EFI_RESET_WARM:
  596         case EFI_RESET_SHUTDOWN:
  597                 break;
  598         default:
  599                 return (EINVAL);
  600         }
  601         if (efi_runtime == NULL)
  602                 return (ENXIO);
  603         bzero(&ec, sizeof(ec));
  604         ec.ec_name = "rt_reset";
  605         ec.ec_argcnt = 4;
  606         ec.ec_arg1 = (uintptr_t)type;
  607         ec.ec_arg2 = (uintptr_t)0;
  608         ec.ec_arg3 = (uintptr_t)0;
  609         ec.ec_arg4 = (uintptr_t)NULL;
  610         ec.ec_fptr = EFI_RT_METHOD_PA(rt_reset);
  611         return (efi_call(&ec));
  612 }
  613 
  614 static int
  615 efi_set_time_locked(struct efi_tm *tm)
  616 {
  617         struct efirt_callinfo ec;
  618 
  619         EFI_TIME_OWNED();
  620         if (efi_runtime == NULL)
  621                 return (ENXIO);
  622         bzero(&ec, sizeof(ec));
  623         ec.ec_name = "rt_settime";
  624         ec.ec_argcnt = 1;
  625         ec.ec_arg1 = (uintptr_t)tm;
  626         ec.ec_fptr = EFI_RT_METHOD_PA(rt_settime);
  627         return (efi_call(&ec));
  628 }
  629 
  630 static int
  631 set_time(struct efi_tm *tm)
  632 {
  633         int error;
  634 
  635         if (efi_runtime == NULL)
  636                 return (ENXIO);
  637         EFI_TIME_LOCK();
  638         error = efi_set_time_locked(tm);
  639         EFI_TIME_UNLOCK();
  640         return (error);
  641 }
  642 
  643 static int
  644 var_get(efi_char *name, struct uuid *vendor, uint32_t *attrib,
  645     size_t *datasize, void *data)
  646 {
  647         struct efirt_callinfo ec;
  648         int error;
  649 
  650         if (efi_runtime == NULL)
  651                 return (ENXIO);
  652         bzero(&ec, sizeof(ec));
  653         ec.ec_argcnt = 5;
  654         ec.ec_name = "rt_getvar";
  655         ec.ec_arg1 = (uintptr_t)name;
  656         ec.ec_arg2 = (uintptr_t)vendor;
  657         ec.ec_arg3 = (uintptr_t)attrib;
  658         ec.ec_arg4 = (uintptr_t)datasize;
  659         ec.ec_arg5 = (uintptr_t)data;
  660         ec.ec_fptr = EFI_RT_METHOD_PA(rt_getvar);
  661         error = efi_call(&ec);
  662         if (error == 0)
  663                 kmsan_mark(data, *datasize, KMSAN_STATE_INITED);
  664         return (error);
  665 }
  666 
  667 static int
  668 var_nextname(size_t *namesize, efi_char *name, struct uuid *vendor)
  669 {
  670         struct efirt_callinfo ec;
  671         int error;
  672 
  673         if (efi_runtime == NULL)
  674                 return (ENXIO);
  675         bzero(&ec, sizeof(ec));
  676         ec.ec_argcnt = 3;
  677         ec.ec_name = "rt_scanvar";
  678         ec.ec_arg1 = (uintptr_t)namesize;
  679         ec.ec_arg2 = (uintptr_t)name;
  680         ec.ec_arg3 = (uintptr_t)vendor;
  681         ec.ec_fptr = EFI_RT_METHOD_PA(rt_scanvar);
  682         error = efi_call(&ec);
  683         if (error == 0)
  684                 kmsan_mark(name, *namesize, KMSAN_STATE_INITED);
  685         return (error);
  686 }
  687 
  688 static int
  689 var_set(efi_char *name, struct uuid *vendor, uint32_t attrib,
  690     size_t datasize, void *data)
  691 {
  692         struct efirt_callinfo ec;
  693 
  694         if (efi_runtime == NULL)
  695                 return (ENXIO);
  696         bzero(&ec, sizeof(ec));
  697         ec.ec_argcnt = 5;
  698         ec.ec_name = "rt_setvar";
  699         ec.ec_arg1 = (uintptr_t)name;
  700         ec.ec_arg2 = (uintptr_t)vendor;
  701         ec.ec_arg3 = (uintptr_t)attrib;
  702         ec.ec_arg4 = (uintptr_t)datasize;
  703         ec.ec_arg5 = (uintptr_t)data;
  704         ec.ec_fptr = EFI_RT_METHOD_PA(rt_setvar);
  705         return (efi_call(&ec));
  706 }
  707 
  708 const static struct efi_ops efi_ops = {
  709         .rt_ok = rt_ok,
  710         .get_table = get_table,
  711         .copy_table = copy_table,
  712         .get_time = get_time,
  713         .get_time_capabilities = get_time_capabilities,
  714         .reset_system = reset_system,
  715         .set_time = set_time,
  716         .var_get = var_get,
  717         .var_nextname = var_nextname,
  718         .var_set = var_set,
  719 };
  720 const struct efi_ops *active_efi_ops = &efi_ops;
  721 
  722 static int
  723 efirt_modevents(module_t m, int event, void *arg __unused)
  724 {
  725 
  726         switch (event) {
  727         case MOD_LOAD:
  728                 return (efi_init());
  729 
  730         case MOD_UNLOAD:
  731                 efi_uninit();
  732                 return (0);
  733 
  734         case MOD_SHUTDOWN:
  735                 return (0);
  736 
  737         default:
  738                 return (EOPNOTSUPP);
  739         }
  740 }
  741 
  742 static moduledata_t efirt_moddata = {
  743         .name = "efirt",
  744         .evhand = efirt_modevents,
  745         .priv = NULL,
  746 };
  747 /* After fpuinitstate, before efidev */
  748 DECLARE_MODULE(efirt, efirt_moddata, SI_SUB_DRIVERS, SI_ORDER_SECOND);
  749 MODULE_VERSION(efirt, 1);

Cache object: 0c2db95535edcc3b2afbde9dcc049213


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.