Dear Sergii and others, I've committed the change that passes the ESRT from the bootloader to the kernel. So now it is time to add the interfaces to the kernel to read it. And add the interfaces to manipulate EFI variables.
For those out of the loop: this could allow us to run fwupd on OpenBSD, bringing us a way to update the firmware on many machines without running through several hoops like booting Windows. What it will also allow us to do is properly set a boot option for OpenBSD and place it at the fron of the list. Setting EFI variables is only allowed at securelevel 0 and below. This diff is an adaptation of the code that Sergii wrote: https://marc.info/?l=openbsd-tech&m=166405001006952&w=2 A few notable changes I made to that code: * This also adds support for arm64 * Uses a different device major for /dev/efi since I used an unused number in the middle of the table. * Renumbered some of the ioctls to avoid leaving a gap * Made <dev/efi/efiio.h> self-contained. * Fixed the copyright on <dev/efi/efiio.h> to match the FreeBSD file from which significant chunks were copied. * Reworked the error handling a bit, reducing the errors to those that actually can happen according to the EFI spec. Other than the location of the header file, this should all be consistent with the interfaces that FreeBSD and NetBSD provide. ok? Index: etc/MAKEDEV.common =================================================================== RCS file: /cvs/src/etc/MAKEDEV.common,v retrieving revision 1.118 diff -u -p -r1.118 MAKEDEV.common --- etc/MAKEDEV.common 10 Nov 2022 09:50:00 -0000 1.118 +++ etc/MAKEDEV.common 4 Jan 2023 19:44:01 -0000 @@ -533,3 +533,5 @@ __devitem(dt, dt, Dynamic Tracer)dnl _mkdev(dt, dt, {-M dt c major_dt_c 0 600-})dnl __devitem(kstat, kstat, Kernel Statistics)dnl _mkdev(kstat, kstat, {-M kstat c major_kstat_c 0 640-})dnl +__devitem(efi, efi, EFI runtime services)dnl +_mkdev(efi, efi, {-M efi c major_efi_c 0 600-})dnl Index: etc/etc.amd64/MAKEDEV =================================================================== RCS file: /cvs/src/etc/etc.amd64/MAKEDEV,v retrieving revision 1.138 diff -u -p -r1.138 MAKEDEV --- etc/etc.amd64/MAKEDEV 10 Nov 2022 11:02:26 -0000 1.138 +++ etc/etc.amd64/MAKEDEV 4 Jan 2023 19:44:01 -0000 @@ -75,6 +75,7 @@ # dt Dynamic Tracer # diskmap Disk mapper # dri Direct Rendering Infrastructure +# efi EFI runtime services # fd fd/* nodes # fuse Userland Filesystem # gpio* General Purpose Input/Output @@ -358,6 +359,10 @@ fd) MKlist[${#MKlist[*]}]=";chmod 555 fd" ;; +efi) + M efi c 84 0 600 + ;; + dri) RMlist[${#RMlist[*]}]=";mkdir -p dri;rm -f" n=0 @@ -593,19 +598,19 @@ local) ;; all) - R ipmi0 ttyVI00 ttyVI10 ttyVI20 ttyVI30 ttyVI40 dri nvram - R gpio0 gpio1 gpio2 bktr0 vnd0 vnd1 vnd2 vnd3 sd0 sd1 sd2 sd3 - R sd4 sd5 sd6 sd7 sd8 sd9 cd0 cd1 rd0 tap0 tap1 tap2 tap3 tun0 - R tun1 tun2 tun3 bio pty0 fd1 fd1B fd1C fd1D fd1E fd1F fd1G - R fd1H fd0 fd0B fd0C fd0D fd0E fd0F fd0G fd0H diskmap vscsi0 - R ch0 audio0 audio1 audio2 audio3 kstat dt kcov bpf pvbus0 - R pvbus1 vmm fuse pppac pppx hotplug ptm local wscons pci0 - R pci1 pci2 pci3 uall rmidi0 rmidi1 rmidi2 rmidi3 rmidi4 - R rmidi5 rmidi6 rmidi7 tuner0 radio0 speaker video0 video1 uk0 - R random lpa0 lpa1 lpa2 lpt0 lpt1 lpt2 tty00 tty01 tty02 tty03 - R tty04 tty05 tty06 tty07 tty08 tty09 tty0a tty0b ttyc0 ttyc1 - R ttyc2 ttyc3 ttyc4 ttyc5 ttyc6 ttyc7 apm pf pctr wd0 wd1 wd2 - R wd3 std st0 st1 fd + R efi0 ipmi0 ttyVI00 ttyVI10 ttyVI20 ttyVI30 ttyVI40 dri + R nvram gpio0 gpio1 gpio2 bktr0 vnd0 vnd1 vnd2 vnd3 sd0 sd1 + R sd2 sd3 sd4 sd5 sd6 sd7 sd8 sd9 cd0 cd1 rd0 tap0 tap1 tap2 + R tap3 tun0 tun1 tun2 tun3 bio pty0 fd1 fd1B fd1C fd1D fd1E + R fd1F fd1G fd1H fd0 fd0B fd0C fd0D fd0E fd0F fd0G fd0H + R diskmap vscsi0 ch0 audio0 audio1 audio2 audio3 kstat dt kcov + R bpf pvbus0 pvbus1 vmm fuse pppac pppx hotplug ptm local + R wscons pci0 pci1 pci2 pci3 uall rmidi0 rmidi1 rmidi2 rmidi3 + R rmidi4 rmidi5 rmidi6 rmidi7 tuner0 radio0 speaker video0 + R video1 uk0 random lpa0 lpa1 lpa2 lpt0 lpt1 lpt2 tty00 tty01 + R tty02 tty03 tty04 tty05 tty06 tty07 tty08 tty09 tty0a tty0b + R ttyc0 ttyc1 ttyc2 ttyc3 ttyc4 ttyc5 ttyc6 ttyc7 apm pf pctr + R wd0 wd1 wd2 wd3 std st0 st1 fd ;; wd*|sd*) Index: etc/etc.amd64/MAKEDEV.md =================================================================== RCS file: /cvs/src/etc/etc.amd64/MAKEDEV.md,v retrieving revision 1.81 diff -u -p -r1.81 MAKEDEV.md --- etc/etc.amd64/MAKEDEV.md 9 Nov 2022 19:35:23 -0000 1.81 +++ etc/etc.amd64/MAKEDEV.md 4 Jan 2023 19:44:01 -0000 @@ -72,6 +72,7 @@ _DEV(bpf, 23) _DEV(dt, 30) _DEV(diskmap, 90) _DEV(dri, 87) +_DEV(efi, 84) _DEV(fdesc, 22) _DEV(fuse, 92) _DEV(gpio, 88) @@ -137,5 +138,6 @@ target(all, nvram)dnl target(all, dri)dnl target(all, ttyVI, 00, 10, 20, 30, 40)dnl target(all, ipmi, 0)dnl +target(all, efi, 0)dnl twrget(ramd, wsdisp, ttyC, 0)dnl target(ramd, fd, 0)dnl Index: etc/etc.arm64/MAKEDEV.md =================================================================== RCS file: /cvs/src/etc/etc.arm64/MAKEDEV.md,v retrieving revision 1.15 diff -u -p -r1.15 MAKEDEV.md --- etc/etc.arm64/MAKEDEV.md 9 Nov 2022 19:35:23 -0000 1.15 +++ etc/etc.arm64/MAKEDEV.md 4 Jan 2023 19:44:01 -0000 @@ -64,6 +64,7 @@ _DEV(bpf, 23) _DEV(dt, 30) _DEV(diskmap, 90) _DEV(dri, 87) +_DEV(efi, 71) _DEV(fdesc, 22) _DEV(fuse, 92) _DEV(gpio, 88) Index: share/man/man8/man8.amd64/MAKEDEV.8 =================================================================== RCS file: /cvs/src/share/man/man8/man8.amd64/MAKEDEV.8,v retrieving revision 1.96 diff -u -p -r1.96 MAKEDEV.8 --- share/man/man8/man8.amd64/MAKEDEV.8 10 Nov 2022 11:02:27 -0000 1.96 +++ share/man/man8/man8.amd64/MAKEDEV.8 4 Jan 2023 19:44:26 -0000 @@ -1,4 +1,4 @@ -.\" $OpenBSD: MAKEDEV.8,v 1.96 2022/11/10 11:02:27 krw Exp $ +.\" $OpenBSD$ .\" .\" THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. .\" generated from: @@ -23,7 +23,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: November 10 2022 $ +.Dd $Mdocdate: June 6 2017 $ .Dt MAKEDEV 8 amd64 .Os .Sh NAME @@ -221,6 +221,9 @@ Disk mapper, see .It Ar dri Direct Rendering Infrastructure, see .Xr drm 4 . +.It Ar efi +EFI runtime services, see +.Xr efi 4 . .It Ar fd fd/* nodes, see .Xr fd 4 . Index: sys/arch/amd64/amd64/conf.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/conf.c,v retrieving revision 1.76 diff -u -p -r1.76 conf.c --- sys/arch/amd64/amd64/conf.c 2 Sep 2022 20:06:55 -0000 1.76 +++ sys/arch/amd64/amd64/conf.c 4 Jan 2023 19:44:26 -0000 @@ -173,6 +173,7 @@ cdev_decl(pci); #include "fuse.h" #include "pvbus.h" #include "ipmi.h" +#include "efi.h" struct cdevsw cdevsw[] = { @@ -272,7 +273,7 @@ struct cdevsw cdevsw[] = cdev_ptm_init(NPTY,ptm), /* 81: pseudo-tty ptm device */ cdev_hotplug_init(NHOTPLUG,hotplug), /* 82: devices hot plugging */ cdev_acpi_init(NACPI,acpi), /* 83: ACPI */ - cdev_notdef(), + cdev_efi_init(NEFI,efi), /* 84: EFI */ cdev_nvram_init(NNVRAM,nvram), /* 85: NVRAM interface */ cdev_notdef(), /* 86 */ cdev_drm_init(NDRM,drm), /* 87: drm */ Index: sys/arch/amd64/amd64/efi_machdep.c =================================================================== RCS file: /cvs/src/sys/arch/amd64/amd64/efi_machdep.c,v retrieving revision 1.4 diff -u -p -r1.4 efi_machdep.c --- sys/arch/amd64/amd64/efi_machdep.c 7 Nov 2022 01:41:57 -0000 1.4 +++ sys/arch/amd64/amd64/efi_machdep.c 4 Jan 2023 19:44:26 -0000 @@ -28,21 +28,10 @@ extern paddr_t cr3_reuse_pcid; #include <dev/efi/efi.h> - -#include <dev/clock_subr.h> +#include <machine/efivar.h> extern EFI_MEMORY_DESCRIPTOR *mmap; -struct efi_softc { - struct device sc_dev; - struct pmap *sc_pm; - EFI_RUNTIME_SERVICES *sc_rs; - u_long sc_psw; - uint64_t sc_cr3; - - struct todr_chip_handle sc_todr; -}; - int efi_match(struct device *, void *, void *); void efi_attach(struct device *, struct device *, void *); @@ -50,21 +39,12 @@ const struct cfattach efi_ca = { sizeof(struct efi_softc), efi_match, efi_attach }; -struct cfdriver efi_cd = { - NULL, "efi", DV_DULL -}; - void efi_map_runtime(struct efi_softc *); -void efi_enter(struct efi_softc *); -void efi_leave(struct efi_softc *); int efi_gettime(struct todr_chip_handle *, struct timeval *); int efi_settime(struct todr_chip_handle *, struct timeval *); label_t efi_jmpbuf; -#define efi_enter_check(sc) (setjmp(&efi_jmpbuf) ? \ - (efi_leave(sc), EFAULT) : (efi_enter(sc), 0)) - int efi_match(struct device *parent, void *match, void *aux) { @@ -123,6 +103,9 @@ efi_attach(struct device *parent, struct if ((bios_efiinfo->flags & BEI_64BIT) == 0) return; + + if (bios_efiinfo->flags & BEI_ESRT) + sc->sc_esrt = (void *)bios_efiinfo->config_esrt; efi_map_runtime(sc); Index: sys/arch/amd64/conf/files.amd64 =================================================================== RCS file: /cvs/src/sys/arch/amd64/conf/files.amd64,v retrieving revision 1.106 diff -u -p -r1.106 files.amd64 --- sys/arch/amd64/conf/files.amd64 16 Oct 2022 15:03:39 -0000 1.106 +++ sys/arch/amd64/conf/files.amd64 4 Jan 2023 19:44:26 -0000 @@ -245,9 +245,9 @@ file arch/amd64/pci/acpipci.c acpipci # # EFI # -device efi +include "dev/efi/files.efi" attach efi at bios -file arch/amd64/amd64/efi_machdep.c efi needs-flag +file arch/amd64/amd64/efi_machdep.c efi # # VMM Index: sys/arch/amd64/include/efivar.h =================================================================== RCS file: sys/arch/amd64/include/efivar.h diff -N sys/arch/amd64/include/efivar.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/amd64/include/efivar.h 4 Jan 2023 19:44:26 -0000 @@ -0,0 +1,42 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2022 Mark Kettenis <kette...@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_EFIVAR_H_ +#define _MACHINE_EFIVAR_H_ + +#include <dev/clock_subr.h> + +struct efi_softc { + struct device sc_dev; + struct pmap *sc_pm; + EFI_RUNTIME_SERVICES *sc_rs; + EFI_SYSTEM_RESOURCE_TABLE *sc_esrt; + u_long sc_psw; + uint64_t sc_cr3; + + struct todr_chip_handle sc_todr; +}; + +void efi_enter(struct efi_softc *); +void efi_leave(struct efi_softc *); + +extern label_t efi_jmpbuf; + +#define efi_enter_check(sc) (setjmp(&efi_jmpbuf) ? \ + (efi_leave(sc), EFAULT) : (efi_enter(sc), 0)) + +#endif /* _MACHINE_EFIVAR_H_ */ Index: sys/arch/arm64/arm64/conf.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/arm64/conf.c,v retrieving revision 1.20 diff -u -p -r1.20 conf.c --- sys/arch/arm64/arm64/conf.c 2 Sep 2022 20:06:55 -0000 1.20 +++ sys/arch/arm64/arm64/conf.c 4 Jan 2023 19:44:27 -0000 @@ -121,6 +121,7 @@ cdev_decl(pci); #include "openprom.h" #include "gpio.h" #include "ipmi.h" +#include "efi.h" struct cdevsw cdevsw[] = { @@ -199,7 +200,7 @@ struct cdevsw cdevsw[] = wsmouse), cdev_mouse_init(NWSMUX, wsmux), /* 69: ws multiplexor */ cdev_openprom_init(NOPENPROM,openprom), /* 70: /dev/openprom */ - cdev_notdef(), /* 71: was: Cyclades-Z serial port */ + cdev_efi_init(NEFI,efi), /* 71: EFI */ #ifdef USER_PCICONF cdev_pci_init(NPCI,pci), /* 72: PCI user */ #else Index: sys/arch/arm64/conf/files.arm64 =================================================================== RCS file: /cvs/src/sys/arch/arm64/conf/files.arm64,v retrieving revision 1.65 diff -u -p -r1.65 files.arm64 --- sys/arch/arm64/conf/files.arm64 17 Dec 2022 11:56:44 -0000 1.65 +++ sys/arch/arm64/conf/files.arm64 4 Jan 2023 19:44:27 -0000 @@ -63,9 +63,10 @@ device simplebus: fdt attach simplebus at fdt file arch/arm64/dev/simplebus.c simplebus -device efi {} +# EFI +include "dev/efi/files.efi" attach efi at fdt -file arch/arm64/dev/efi_machdep.c efi needs-flag +file arch/arm64/dev/efi_machdep.c efi device smbios attach smbios at efi Index: sys/arch/arm64/dev/efi_machdep.c =================================================================== RCS file: /cvs/src/sys/arch/arm64/dev/efi_machdep.c,v retrieving revision 1.5 diff -u -p -r1.5 efi_machdep.c --- sys/arch/arm64/dev/efi_machdep.c 6 Nov 2022 11:44:30 -0000 1.5 +++ sys/arch/arm64/dev/efi_machdep.c 4 Jan 2023 19:44:27 -0000 @@ -32,8 +32,7 @@ #include <dev/ofw/fdt.h> #include <dev/efi/efi.h> - -#include <dev/clock_subr.h> +#include <machine/efivar.h> /* * We need a large address space to allow identity mapping of physical @@ -50,15 +49,6 @@ extern EFI_MEMORY_DESCRIPTOR *mmap; uint64_t efi_acpi_table; uint64_t efi_smbios_table; -struct efi_softc { - struct device sc_dev; - struct pmap *sc_pm; - EFI_RUNTIME_SERVICES *sc_rs; - u_long sc_psw; - - struct todr_chip_handle sc_todr; -}; - int efi_match(struct device *, void *, void *); void efi_attach(struct device *, struct device *, void *); @@ -66,20 +56,11 @@ const struct cfattach efi_ca = { sizeof(struct efi_softc), efi_match, efi_attach }; -struct cfdriver efi_cd = { - NULL, "efi", DV_DULL -}; - void efi_map_runtime(struct efi_softc *); -void efi_enter(struct efi_softc *); -void efi_leave(struct efi_softc *); int efi_gettime(struct todr_chip_handle *, struct timeval *); int efi_settime(struct todr_chip_handle *, struct timeval *); label_t efi_jmpbuf; - -#define efi_enter_check(sc) (setjmp(&efi_jmpbuf) ? \ - (efi_leave(sc), EFAULT) : (efi_enter(sc), 0)) int efi_match(struct device *parent, void *match, void *aux) Index: sys/arch/arm64/include/efivar.h =================================================================== RCS file: sys/arch/arm64/include/efivar.h diff -N sys/arch/arm64/include/efivar.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/arm64/include/efivar.h 4 Jan 2023 19:44:27 -0000 @@ -0,0 +1,41 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2022 Mark Kettenis <kette...@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_EFIVAR_H_ +#define _MACHINE_EFIVAR_H_ + +#include <dev/clock_subr.h> + +struct efi_softc { + struct device sc_dev; + struct pmap *sc_pm; + EFI_RUNTIME_SERVICES *sc_rs; + EFI_SYSTEM_RESOURCE_TABLE *sc_esrt; + u_long sc_psw; + + struct todr_chip_handle sc_todr; +}; + +void efi_enter(struct efi_softc *); +void efi_leave(struct efi_softc *); + +extern label_t efi_jmpbuf; + +#define efi_enter_check(sc) (setjmp(&efi_jmpbuf) ? \ + (efi_leave(sc), EFAULT) : (efi_enter(sc), 0)) + +#endif /* _MACHINE_EFIVAR_H_ */ Index: sys/dev/efi/efi.c =================================================================== RCS file: sys/dev/efi/efi.c diff -N sys/dev/efi/efi.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/efi/efi.c 4 Jan 2023 19:44:27 -0000 @@ -0,0 +1,284 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2022 3mdeb <cont...@3mdeb.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#include <dev/efi/efi.h> +#include <dev/efi/efiio.h> +#include <machine/efivar.h> + +struct cfdriver efi_cd = { + NULL, "efi", DV_DULL +}; + +int efiioc_get_table(struct efi_softc *sc, void *); +int efiioc_var_get(struct efi_softc *sc, void *); +int efiioc_var_next(struct efi_softc *sc, void *); +int efiioc_var_set(struct efi_softc *sc, void *); +int efi_adapt_error(EFI_STATUS); + +int +efiopen(dev_t dev, int flag, int mode, struct proc *p) +{ + return (efi_cd.cd_ndevs > 0 ? 0 : ENXIO); +} + +int +eficlose(dev_t dev, int flag, int mode, struct proc *p) +{ + return 0; +} + +int +efiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct efi_softc *sc = efi_cd.cd_devs[0]; + int error; + + switch (cmd) { + case EFIIOC_GET_TABLE: + error = efiioc_get_table(sc, data); + break; + case EFIIOC_VAR_GET: + error = efiioc_var_get(sc, data); + break; + case EFIIOC_VAR_NEXT: + error = efiioc_var_next(sc, data); + break; + case EFIIOC_VAR_SET: + error = efiioc_var_set(sc, data); + break; + default: + error = ENOTTY; + break; + } + + return error; +} + +int +efiioc_get_table(struct efi_softc *sc, void *data) +{ + EFI_GUID esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID; + struct efi_get_table_ioc *ioc = data; + char *buf = NULL; + int error; + + /* Only ESRT is supported at the moment. */ + if (memcmp(&ioc->uuid, &esrt_guid, sizeof(ioc->uuid)) != 0) + return EINVAL; + + /* ESRT might not be present. */ + if (sc->sc_esrt == NULL) + return ENXIO; + + if (efi_enter_check(sc)) { + free(buf, M_TEMP, ioc->table_len); + return ENOSYS; + } + + ioc->table_len = sizeof(*sc->sc_esrt) + + sizeof(EFI_SYSTEM_RESOURCE_ENTRY) * sc->sc_esrt->FwResourceCount; + + /* Return table length to userspace. */ + if (ioc->buf == NULL) { + efi_leave(sc); + return 0; + } + + /* Refuse to copy only part of the table. */ + if (ioc->buf_len < ioc->table_len) { + efi_leave(sc); + return EINVAL; + } + + buf = malloc(ioc->table_len, M_TEMP, M_WAITOK); + memcpy(buf, sc->sc_esrt, ioc->table_len); + + efi_leave(sc); + + error = copyout(buf, ioc->buf, ioc->table_len); + free(buf, M_TEMP, ioc->table_len); + + return error; +} + +int +efiioc_var_get(struct efi_softc *sc, void *data) +{ + struct efi_var_ioc *ioc = data; + void *value = NULL; + efi_char *name = NULL; + size_t valuesize = ioc->datasize; + EFI_STATUS status; + int error; + + if (valuesize > 0) + value = malloc(valuesize, M_TEMP, M_WAITOK); + name = malloc(ioc->namesize, M_TEMP, M_WAITOK); + error = copyin(ioc->name, name, ioc->namesize); + if (error != 0) + goto leave; + + /* NULL-terminated name must fit into namesize bytes. */ + if (name[ioc->namesize / sizeof(*name) - 1] != 0) { + error = EINVAL; + goto leave; + } + + if (efi_enter_check(sc)) { + error = ENOSYS; + goto leave; + } + status = sc->sc_rs->GetVariable(name, (EFI_GUID *)&ioc->vendor, + &ioc->attrib, &ioc->datasize, value); + efi_leave(sc); + + if (status == EFI_BUFFER_TOO_SMALL) { + /* + * Return size of the value, which was set by EFI RT, + * reporting no error to match FreeBSD's behaviour. + */ + ioc->data = NULL; + goto leave; + } + + error = efi_adapt_error(status); + if (error == 0) + error = copyout(value, ioc->data, ioc->datasize); + +leave: + free(value, M_TEMP, valuesize); + free(name, M_TEMP, ioc->namesize); + return error; +} + +int +efiioc_var_next(struct efi_softc *sc, void *data) +{ + struct efi_var_ioc *ioc = data; + efi_char *name; + size_t namesize = ioc->namesize; + EFI_STATUS status; + int error; + + name = malloc(namesize, M_TEMP, M_WAITOK); + error = copyin(ioc->name, name, namesize); + if (error) + goto leave; + + if (efi_enter_check(sc)) { + error = ENOSYS; + goto leave; + } + status = sc->sc_rs->GetNextVariableName(&ioc->namesize, + name, (EFI_GUID *)&ioc->vendor); + efi_leave(sc); + + if (status == EFI_BUFFER_TOO_SMALL) { + /* + * Return size of the name, which was set by EFI RT, + * reporting no error to match FreeBSD's behaviour. + */ + ioc->name = NULL; + goto leave; + } + + error = efi_adapt_error(status); + if (error == 0) + error = copyout(name, ioc->name, ioc->namesize); + +leave: + free(name, M_TEMP, namesize); + return error; +} + +int +efiioc_var_set(struct efi_softc *sc, void *data) +{ + struct efi_var_ioc *ioc = data; + void *value = NULL; + efi_char *name = NULL; + EFI_STATUS status; + int error; + + /* Zero datasize means variable deletion. */ + if (ioc->datasize > 0) { + value = malloc(ioc->datasize, M_TEMP, M_WAITOK); + error = copyin(ioc->data, value, ioc->datasize); + if (error) + goto leave; + } + + name = malloc(ioc->namesize, M_TEMP, M_WAITOK); + error = copyin(ioc->name, name, ioc->namesize); + if (error) + goto leave; + + /* NULL-terminated name must fit into namesize bytes. */ + if (name[ioc->namesize / sizeof(*name) - 1] != 0) { + error = EINVAL; + goto leave; + } + + if (securelevel > 0) { + error = EPERM; + goto leave; + } + + if (efi_enter_check(sc)) { + error = ENOSYS; + goto leave; + } + status = sc->sc_rs->SetVariable(name, (EFI_GUID *)&ioc->vendor, + ioc->attrib, ioc->datasize, value); + efi_leave(sc); + + error = efi_adapt_error(status); + +leave: + free(value, M_TEMP, ioc->datasize); + free(name, M_TEMP, ioc->namesize); + return error; +} + +int +efi_adapt_error(EFI_STATUS status) +{ + switch (status) { + case EFI_SUCCESS: + return 0; + case EFI_DEVICE_ERROR: + return EIO; + case EFI_INVALID_PARAMETER: + return EINVAL; + case EFI_NOT_FOUND: + return ENOENT; + case EFI_OUT_OF_RESOURCES: + return EAGAIN; + case EFI_SECURITY_VIOLATION: + return EPERM; + case EFI_UNSUPPORTED: + return ENOSYS; + case EFI_WRITE_PROTECTED: + return EROFS; + default: + return EIO; + } +} Index: sys/dev/efi/efi.h =================================================================== RCS file: /cvs/src/sys/dev/efi/efi.h,v retrieving revision 1.3 diff -u -p -r1.3 efi.h --- sys/dev/efi/efi.h 18 Oct 2022 10:17:56 -0000 1.3 +++ sys/dev/efi/efi.h 4 Jan 2023 19:44:27 -0000 @@ -11,6 +11,12 @@ #define EFIAPI #endif +#ifdef __LP64__ +#define EFIERR(x) (0x8000000000000000 | (x)) +#else +#define EFIERR(x) (0x80000000 | (x)) +#endif + typedef uint8_t UINT8; typedef int16_t INT16; typedef uint16_t UINT16; @@ -47,6 +53,10 @@ typedef struct { { 0xf2fd1544, 0x9794, 0x4a2c, \ { 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 } } +#define EFI_SYSTEM_RESOURCE_TABLE_GUID \ + { 0xb122a263, 0x3661, 0x4f68, \ + { 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 } } + #define EFI_GLOBAL_VARIABLE \ { 0x8be4df61, 0x93ca, 0x11d2, \ { 0xaa,0x0d,0x00,0xe0,0x98,0x03,0x2b,0x8c } } @@ -175,7 +185,33 @@ typedef struct { EFI_CONFIGURATION_TABLE *ConfigurationTable; } EFI_SYSTEM_TABLE; +typedef struct { + EFI_GUID FwClass; + UINT32 FwType; + UINT32 FwVersion; + UINT32 LowestSupportedFwVersion; + UINT32 CapsuleFlags; + UINT32 LastAttemptVersion; + UINT32 LastAttemptStatus; +} EFI_SYSTEM_RESOURCE_ENTRY; + +typedef struct { + UINT32 FwResourceCount; + UINT32 FwResourceCountMax; + UINT64 FwResourceVersion; + EFI_SYSTEM_RESOURCE_ENTRY Entries[]; +} EFI_SYSTEM_RESOURCE_TABLE; + #define EFI_SUCCESS 0 + +#define EFI_INVALID_PARAMETER EFIERR(2) +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_BUFFER_TOO_SMALL EFIERR(5) +#define EFI_DEVICE_ERROR EFIERR(7) +#define EFI_WRITE_PROTECTED EFIERR(8) +#define EFI_OUT_OF_RESOURCES EFIERR(9) +#define EFI_NOT_FOUND EFIERR(14) +#define EFI_SECURITY_VIOLATION EFIERR(26) #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) Index: sys/dev/efi/efiio.h =================================================================== RCS file: sys/dev/efi/efiio.h diff -N sys/dev/efi/efiio.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/efi/efiio.h 4 Jan 2023 19:44:27 -0000 @@ -0,0 +1,82 @@ +/* $OpenBSD$ */ +/*- + * Copyright (c) 2016 Netflix, Inc. + * Copyright (c) 2022 3mdeb <cont...@3mdeb.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_EFI_EFIIO_H_ +#define _DEV_EFI_EFIIO_H_ + +#include <sys/types.h> +#include <sys/ioccom.h> +#include <sys/uuid.h> + +typedef uint16_t efi_char; + +#define EFI_TABLE_ESRT \ + {0xb122a263,0x3661,0x4f68,0x99,0x29,{0x78,0xf8,0xb0,0xd6,0x21,0x80}} + +struct efi_esrt_table { + uint32_t fw_resource_count; + uint32_t fw_resource_count_max; + uint64_t fw_resource_version; +#define ESRT_FIRMWARE_RESOURCE_VERSION 1 + uint8_t entries[]; +}; + +struct efi_esrt_entry_v1 { + struct uuid fw_class; + uint32_t fw_type; + uint32_t fw_version; + uint32_t lowest_supported_fw_version; + uint32_t capsule_flags; + uint32_t last_attempt_version; + uint32_t last_attempt_status; +}; + +struct efi_get_table_ioc +{ + void *buf; /* Pointer to userspace buffer */ + struct uuid uuid; /* UUID to look up */ + size_t table_len; /* Table size */ + size_t buf_len; /* Size of the buffer */ +}; + +struct efi_var_ioc +{ + uint16_t *name; /* User pointer to name, in UCS2 chars */ + size_t namesize; /* Number of *bytes* in the name including + terminator */ + struct uuid vendor; /* Vendor's UUID for variable */ + uint32_t attrib; /* Attributes */ + void *data; /* User pointer to value */ + size_t datasize; /* Number of *bytes* in the value */ +}; + +#define EFIIOC_GET_TABLE _IOWR('E', 1, struct efi_get_table_ioc) +#define EFIIOC_VAR_GET _IOWR('E', 2, struct efi_var_ioc) +#define EFIIOC_VAR_NEXT _IOWR('E', 3, struct efi_var_ioc) +#define EFIIOC_VAR_SET _IOWR('E', 4, struct efi_var_ioc) + +#endif /* _DEV_EFI_EFIIO_H_ */ Index: sys/dev/efi/files.efi =================================================================== RCS file: sys/dev/efi/files.efi diff -N sys/dev/efi/files.efi --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/efi/files.efi 4 Jan 2023 19:44:27 -0000 @@ -0,0 +1,7 @@ +# $OpenBSD: files.acpi,v 1.67 2022/11/06 15:36:13 patrick Exp $ +# +# Config file and device description for machine-independent ACPI code. +# Included by ports that need it. + +device efi {} +file dev/efi/efi.c efi needs-flag Index: sys/sys/conf.h =================================================================== RCS file: /cvs/src/sys/sys/conf.h,v retrieving revision 1.160 diff -u -p -r1.160 conf.h --- sys/sys/conf.h 6 Nov 2022 13:03:52 -0000 1.160 +++ sys/sys/conf.h 4 Jan 2023 19:44:29 -0000 @@ -481,6 +481,13 @@ extern struct cdevsw cdevsw[]; (dev_type_stop((*))) enodev, 0, (dev_type_mmap((*))) enodev, \ 0, 0, seltrue_kqfilter } +/* open, close, ioctl */ +#define cdev_efi_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, \ + (dev_type_mmap((*))) enodev } + /* open, close, ioctl, mmap */ #define cdev_kcov_init(c,n) { \ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ @@ -632,6 +639,7 @@ cdev_decl(amdmsr); cdev_decl(fuse); cdev_decl(pvbus); cdev_decl(ipmi); +cdev_decl(efi); cdev_decl(kcov); #endif