Hello NetBSD devs,
Background
----------
As some might know, FreeBSD gained an interface for querying ESRT about a
year ago ([1], [2]), which was done as part of [3].
[1]: https://reviews.freebsd.org/rGd12d651f8692cfcaf6fd0a6e8264c29547f644c9
[2]: https://reviews.freebsd.org/rG24f398e7a153a05a7e94ae8dd623e2b6d28d94eb
[3]: https://nlnet.nl/project/fwdup-BSD/
Adding it allowed to make UEFI capsule plugin of fwupd [4] work for FreeBSD
[5] to perform firmware updates on EFI systems.
Now it's turn for NetBSD and we would like to ask about requirements and
recommendations on the API and its implementation such that they would be
accepted by the upstream.
[4]: https://fwupd.org/
[5]:
https://github.com/fwupd/fwupd/blob/main/plugins/uefi-capsule/fu-uefi-backend-freebsd.c
The same project is being done for OpenBSD as well [6]
[6]: https://www.mail-archive.com/tech%openbsd.org@localhost/msg70825.html
ESRT
----
The initial idea for accessing ESRT from userland is to use sysctl() like so:
```
void *esrt;
size_t esrt_len;
int mib[] = { CTL_HW, HW_ESRT };
esrt_len = 0;
if (sysctl(mib, 2, NULL, &esrt_len, NULL, 0) == -1 && errno != ENOMEM)
err(1, "sysctl");esrt = malloc(esrt_len);
if (esrt == NULL)
err(1, "malloc");
if (sysctl(mib, 2, esrt, &esrt_len, NULL, 0) == -1)
err(1, "sysctl");
```
However, FreeBSD decided in favour of ioctl() on /dev/efi.
The main question is - where should the implementation of ESRT tables go
into?
Should it be generic and span multiple architectures, or should it be limited
to for example only x86?
I found out that EFI is already handled by the x86 architecture, in
`src/sys/arch/x86/x86/efi.c`. So, the implementation would probably go there
or a new file in the same location, if the decision was to reduce the scope
of this feature to a single arch.
EFI variables
-------------
I don't see an implementation of `efivar` or `efiboot` or anything similar,
so it needs to be added and provide at least this API subset to be usable
with fwupd:
* efi_append_variable() appends data of size to the variable specified by
guid and name
* efi_del_variable() deletes the variable specified by guid and name
* efi_get_variable() gets variable's data_size, and its attributes are stored
in attributes
* efi_get_variable_attributes() gets attributes for the variable specified by
guid and name
* efi_get_variable_size() gets the size of the data for the variable
specified by guid and name
* efi_get_next_variable_name() iterates across the currently extant
variables, passing back a guid and name
* efi_guid_to_name() translates from an efi_guid_t to a well known name
* efi_guid_to_symbol() translates from an efi_guid_t to a unique (within
libefivar) C-style symbol name
* efi_guid_to_str() allocates a suitable string and populates it with string
representation of a UEFI GUID
* efi_name_to_guid() translates from a well known name to an efi_guid_t
* efi_set_variable() sets the variable specified by guid and name
* efi_str_to_guid() parses a UEFI GUID from string form to an efi_guid_t
* efi_variables_supported() checks if EFI variables are accessible
* efi_generate_file_device_path() generates an EFI file device path for an
EFI binary from a filesystem path
Probably should be implemented as a minimal port of efivar [7] with
sufficient functionality rather than a separate project. Either way, this too
needs new kernel API for accessing EFI variables. Will sysctl() do or a new
pseudo-device or is something else needed? Usage of existing implementations
can be seen in FreeBSD [8] and Linux [9] (Linux uses sysfs for this). I also
saw an implementation of a pseudo-driver which allows operations on EFI
variables [10], which would suffice as an API, but unfortunately it wasn't
merged yet. Could it be used in our case?
[7]: https://github.com/rhboot/efivar
[8]:
https://github.com/freebsd/freebsd-src/blob/release/12.2.0/lib/libefivar/efivar.c
[9]: https://github.com/rhboot/efivar/blob/main/src/efivarfs.c
[10]:
https://github.com/NetBSD/src/commit/25ff60a647236a2f67fc08ecac96a14fecffd6f1
Expectations
------------
Please help us shape this API, so the community can be happy with it :)
The implementation is a separate topic, but please let me know if you have
any specific ideas about it right away, so as to help avoid any unnecessary
rounds of reviews.
Kind regards,
Pawel