EFIDEV(4)

πŸ’– EFIDEV πŸ’–

okay so bestie, we're reading EFIDEV(4) today β€” that's the Kernel Interfaces Manual, section 4, the one about talking to your firmware's runtime services from userspace. pull up a chair, grab a strawberry πŸ“, this one's actually so good.


✨ NAME ✨

efidev, efirtc β€” user-mode access to UEFI runtime services 🫢


✨ SYNOPSIS ✨

so like, if you wanna bake this driver straight into your kernel, you drop these lines into your kernel configuration file:

options EFIRT

orrr if you'd rather just load it as a module at boot time (way more chill tbh), you put this line in loader.conf(5):

efirt_load="YES"

and heads up: you can also turn the whole thing off by setting the loader(8) tunable efi.rt.disabled to β€œ1”. no cap.


✨ DESCRIPTION ✨

the efidev device is literally the plug that gives user-mode programs access to UEFI runtime services. it's giving bridge energy.

efidev also includes a driver that provides a time-of-day clock using the UEFI real time clock (RTC). BUT β€” and this is the part everyone forgets 😭 β€” the RTC may not always be available, and whether it is depends entirely on your UEFI firmware. if the RTC isn't available, it will not be registered as a time-of-day clock, and all the time-related ioctls down below will just... not be functional. vibe check failed, sorry.

efidev provides the following ioctls, defined in <sys/efiio.h>, with the supplemental structures and constants living in <sys/efi.h>:

  • EFIIOC_GET_TABLE (struct efi_get_table_ioc) β€” gets you a table by uuid from the UEFI system table. iconic.
struct efi_get_table_ioc {
        struct uuid uuid;
        void *ptr;
};
  • EFIIOC_GET_TIME (struct efi_tm) β€” reads the time from the RTC, if the RTC is available. the struct efi_tm you pass in gets populated with the current time β€” unless an error happens, in which case, well. πŸ™ˆ
struct efi_tm {
        uint16_t        tm_year;
        uint8_t         tm_mon
        uint8_t         tm_mday
        uint8_t         tm_hour;
        uint8_t         tm_min;
        uint8_t         tm_sec;
        uint8_t          __pad1;
        uint32_t        tm_nsec;
        int16_t         tm_tz;
        uint8_t         tm_dst;
        uint8_t         __pad2;
};
  • EFIIOC_SET_TIME (struct efi_tm) β€” sets the time stored by the RTC, if the RTC is available. (see the pattern? RTC availability is the whole plot πŸŽ€)
  • EFIIOC_VAR_GET (struct efi_var_ioc) β€” gets data from the variable described by the vendor and name fields of the struct efi_var_ioc into the data field. it will also populate the attrib field, slay.
struct efi_var_ioc {
        efi_char        *name;
        size_t           namesize;
        struct uuid      vendor;
        uint32_t         attrib;
        void            *data;
        size_t           datasize;
};
  • EFIIOC_VAR_NEXT (struct efi_var_ioc) β€” this one's for enumerating all the UEFI variables. the first call should use an empty string for the name attribute. every call after that should supply the vendor uuid and the name of the last variable that was returned. it's a little chain, iykyk πŸ”—
  • EFIIOC_VAR_SET (struct efi_var_ioc) β€” sets data and attributes for the variable described by the name and vendor in the struct efi_var_ioc. main character energy, honestly.

✨ FILES ✨

  • /dev/efi

✨ SEE ALSO ✨


✨ HISTORY ✨

a efidev device first appeared in FreeBSD 11.1. throwback. πŸ’œ


✨ BUGS ✨

efidev is currently only available on amd64 and arm64. so if you're on something else... not me finding out the hard way πŸ’€

and that's the whole page, bestie! this one's from the Debian crew, dated August 12, 2018 β€” yes, a vintage, and it still ate. πŸ’…βœ¨πŸŒΈ

πŸ“¦ where this page comes from