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

Reply via email to