Module Name: src Committed By: jmcneill Date: Sun Oct 10 13:03:10 UTC 2021
Modified Files: src/distrib/sets/lists/comp: mi src/etc: MAKEDEV.tmpl src/etc/etc.evbarm: MAKEDEV.conf src/sys/arch/arm/arm: efi_runtime.c efi_runtime.h src/sys/arch/arm/fdt: arm_fdt.c src/sys/arch/evbarm/conf: GENERIC64 src/sys/conf: majors src/sys/dev: files.dev src/sys/sys: Makefile Added Files: src/sys/dev: efi.c efivar.h src/sys/sys: efiio.h Log Message: efi: Add /dev/efi character device Introduce a /dev/efi character device that provides a means for accessing UEFI RT variable services from userland. Compatible with the FreeBSD ioctl interface for ease of porting their libefivar and associated tools. The ioctl interface is defined in sys/efiio.h. To enable support for this on an arch, the kernel needs `pseudo-device efi` and the MD EFI implementation needs to register its backend by calling efi_ops_register(). This commit includes an implementation for Arm. To generate a diff of this commit: cvs rdiff -u -r1.2395 -r1.2396 src/distrib/sets/lists/comp/mi cvs rdiff -u -r1.224 -r1.225 src/etc/MAKEDEV.tmpl cvs rdiff -u -r1.21 -r1.22 src/etc/etc.evbarm/MAKEDEV.conf cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/arm/efi_runtime.c cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/arm/efi_runtime.h cvs rdiff -u -r1.19 -r1.20 src/sys/arch/arm/fdt/arm_fdt.c cvs rdiff -u -r1.186 -r1.187 src/sys/arch/evbarm/conf/GENERIC64 cvs rdiff -u -r1.98 -r1.99 src/sys/conf/majors cvs rdiff -u -r0 -r1.1 src/sys/dev/efi.c src/sys/dev/efivar.h cvs rdiff -u -r1.7 -r1.8 src/sys/dev/files.dev cvs rdiff -u -r1.179 -r1.180 src/sys/sys/Makefile cvs rdiff -u -r0 -r1.1 src/sys/sys/efiio.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/comp/mi diff -u src/distrib/sets/lists/comp/mi:1.2395 src/distrib/sets/lists/comp/mi:1.2396 --- src/distrib/sets/lists/comp/mi:1.2395 Thu Sep 30 02:00:19 2021 +++ src/distrib/sets/lists/comp/mi Sun Oct 10 13:03:09 2021 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.2395 2021/09/30 02:00:19 yamaguchi Exp $ +# $NetBSD: mi,v 1.2396 2021/10/10 13:03:09 jmcneill Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. ./etc/mtree/set.comp comp-sys-root @@ -3273,6 +3273,7 @@ ./usr/include/sys/domain.h comp-c-include ./usr/include/sys/drvctlio.h comp-c-include ./usr/include/sys/dvdio.h comp-c-include +./usr/include/sys/efiio.h comp-c-include ./usr/include/sys/elfdefinitions.h comp-c-include ./usr/include/sys/endian.h comp-c-include ./usr/include/sys/envsys.h comp-c-include Index: src/etc/MAKEDEV.tmpl diff -u src/etc/MAKEDEV.tmpl:1.224 src/etc/MAKEDEV.tmpl:1.225 --- src/etc/MAKEDEV.tmpl:1.224 Sat Jul 24 11:39:18 2021 +++ src/etc/MAKEDEV.tmpl Sun Oct 10 13:03:08 2021 @@ -1,5 +1,5 @@ #!/bin/sh - -# $NetBSD: MAKEDEV.tmpl,v 1.224 2021/07/24 11:39:18 jmcneill Exp $ +# $NetBSD: MAKEDEV.tmpl,v 1.225 2021/10/10 13:03:08 jmcneill Exp $ # # Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc. # All rights reserved. @@ -2244,6 +2244,10 @@ smbios) mkdev smbios c %smbios_chr% 0 ;; +efi) + mkdev efi c %efi_chr% 0 660 + ;; + midevend) %MI_DEVICES_END% local) Index: src/etc/etc.evbarm/MAKEDEV.conf diff -u src/etc/etc.evbarm/MAKEDEV.conf:1.21 src/etc/etc.evbarm/MAKEDEV.conf:1.22 --- src/etc/etc.evbarm/MAKEDEV.conf:1.21 Tue Nov 10 08:52:36 2020 +++ src/etc/etc.evbarm/MAKEDEV.conf Sun Oct 10 13:03:09 2021 @@ -1,4 +1,4 @@ -# $NetBSD: MAKEDEV.conf,v 1.21 2020/11/10 08:52:36 rin Exp $ +# $NetBSD: MAKEDEV.conf,v 1.22 2021/10/10 13:03:09 jmcneill Exp $ all_md) makedev wscons fd0 fd1 wd0 wd1 wd2 wd3 sd0 sd1 sd2 sd3 @@ -27,6 +27,7 @@ all_md) makedev spiflash0 makedev bpf makedev openfirm + makedev acpi smbios efi ;; ramdisk|floppy) Index: src/sys/arch/arm/arm/efi_runtime.c diff -u src/sys/arch/arm/arm/efi_runtime.c:1.5 src/sys/arch/arm/arm/efi_runtime.c:1.6 --- src/sys/arch/arm/arm/efi_runtime.c:1.5 Fri Dec 18 07:40:27 2020 +++ src/sys/arch/arm/arm/efi_runtime.c Sun Oct 10 13:03:09 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: efi_runtime.c,v 1.5 2020/12/18 07:40:27 skrll Exp $ */ +/* $NetBSD: efi_runtime.c,v 1.6 2021/10/10 13:03:09 jmcneill Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -29,8 +29,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include "efi.h" + #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: efi_runtime.c,v 1.5 2020/12/18 07:40:27 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: efi_runtime.c,v 1.6 2021/10/10 13:03:09 jmcneill Exp $"); #include <sys/param.h> #include <sys/mutex.h> @@ -38,12 +40,33 @@ __KERNEL_RCSID(0, "$NetBSD: efi_runtime. #include <uvm/uvm_extern.h> +#include <dev/efivar.h> + #include <arm/arm/efi_runtime.h> +#ifdef _LP64 +#define EFIERR(x) (0x8000000000000000 | x) +#else +#define EFIERR(x) (0x80000000 | x) +#endif + +#define EFI_UNSUPPORTED EFIERR(3) +#define EFI_DEVICE_ERROR EFIERR(7) + static kmutex_t efi_lock; static struct efi_rt *RT = NULL; +#if NEFI > 0 && BYTE_ORDER == LITTLE_ENDIAN +static const struct efi_ops arm_efi_ops = { + .efi_gettime = arm_efirt_gettime, + .efi_settime = arm_efirt_settime, + .efi_getvar = arm_efirt_getvar, + .efi_setvar = arm_efirt_setvar, + .efi_nextvar = arm_efirt_nextvar, +}; +#endif + int arm_efirt_init(paddr_t efi_system_table) { @@ -75,6 +98,8 @@ arm_efirt_init(paddr_t efi_system_table) RT = ST->st_rt; mutex_init(&efi_lock, MUTEX_DEFAULT, IPL_HIGH); + efi_register_ops(&arm_efi_ops); + return 0; #else /* EFI runtime not supported in big endian mode */ @@ -82,42 +107,101 @@ arm_efirt_init(paddr_t efi_system_table) #endif } -int -arm_efirt_gettime(struct efi_tm *tm) +efi_status +arm_efirt_gettime(struct efi_tm *tm, struct efi_tmcap *tmcap) { - int error; + efi_status status = EFI_DEVICE_ERROR; - if (RT == NULL || RT->rt_gettime == NULL) - return ENXIO; + if (RT == NULL || RT->rt_gettime == NULL) { + return EFI_UNSUPPORTED; + } mutex_enter(&efi_lock); - if ((error = arm_efirt_md_enter()) == 0) { - if (RT->rt_gettime(tm, NULL) != 0) - error = EIO; + if (arm_efirt_md_enter() == 0) { + status = RT->rt_gettime(tm, tmcap); } arm_efirt_md_exit(); mutex_exit(&efi_lock); - return error; + return status; } -int +efi_status arm_efirt_settime(struct efi_tm *tm) { - int error; + efi_status status = EFI_DEVICE_ERROR; - if (RT == NULL || RT->rt_settime == NULL) - return ENXIO; + if (RT == NULL || RT->rt_settime == NULL) { + return EFI_UNSUPPORTED; + } mutex_enter(&efi_lock); - if ((error = arm_efirt_md_enter()) == 0) { - if (RT->rt_settime(tm) != 0) - error = EIO; + if (arm_efirt_md_enter() == 0) { + status = RT->rt_settime(tm); } arm_efirt_md_exit(); mutex_exit(&efi_lock); - return error; + return status; +} + +efi_status +arm_efirt_getvar(uint16_t *name, struct uuid *vendor, uint32_t *attrib, + u_long *datasize, void *data) +{ + efi_status status = EFI_DEVICE_ERROR; + + if (RT == NULL || RT->rt_getvar == NULL) { + return EFI_UNSUPPORTED; + } + + mutex_enter(&efi_lock); + if (arm_efirt_md_enter() == 0) { + status = RT->rt_getvar(name, vendor, attrib, datasize, data); + } + arm_efirt_md_exit(); + mutex_exit(&efi_lock); + + return status; +} + +efi_status +arm_efirt_nextvar(u_long *namesize, efi_char *name, struct uuid *vendor) +{ + efi_status status = EFI_DEVICE_ERROR; + + if (RT == NULL || RT->rt_scanvar == NULL) { + return EFI_UNSUPPORTED; + } + + mutex_enter(&efi_lock); + if (arm_efirt_md_enter() == 0) { + status = RT->rt_scanvar(namesize, name, vendor); + } + arm_efirt_md_exit(); + mutex_exit(&efi_lock); + + return status; +} + +efi_status +arm_efirt_setvar(uint16_t *name, struct uuid *vendor, uint32_t attrib, + u_long datasize, void *data) +{ + efi_status status = EFI_DEVICE_ERROR; + + if (RT == NULL || RT->rt_setvar == NULL) { + return EFI_UNSUPPORTED; + } + + mutex_enter(&efi_lock); + if (arm_efirt_md_enter() == 0) { + status = RT->rt_setvar(name, vendor, attrib, datasize, data); + } + arm_efirt_md_exit(); + mutex_exit(&efi_lock); + + return status; } int @@ -133,8 +217,9 @@ arm_efirt_reset(enum efi_reset type) if (reset_called == false) { reset_called = true; if ((error = arm_efirt_md_enter()) == 0) { - if (RT->rt_reset(type, 0, 0, NULL) != 0) + if (RT->rt_reset(type, 0, 0, NULL) != 0) { error = EIO; + } } arm_efirt_md_exit(); } else { Index: src/sys/arch/arm/arm/efi_runtime.h diff -u src/sys/arch/arm/arm/efi_runtime.h:1.3 src/sys/arch/arm/arm/efi_runtime.h:1.4 --- src/sys/arch/arm/arm/efi_runtime.h:1.3 Mon Dec 16 00:03:50 2019 +++ src/sys/arch/arm/arm/efi_runtime.h Sun Oct 10 13:03:09 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: efi_runtime.h,v 1.3 2019/12/16 00:03:50 jmcneill Exp $ */ +/* $NetBSD: efi_runtime.h,v 1.4 2021/10/10 13:03:09 jmcneill Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -35,8 +35,13 @@ #include <arm/efi.h> int arm_efirt_init(paddr_t); -int arm_efirt_gettime(struct efi_tm *); -int arm_efirt_settime(struct efi_tm *); +efi_status arm_efirt_gettime(struct efi_tm *, struct efi_tmcap *); +efi_status arm_efirt_settime(struct efi_tm *); +efi_status arm_efirt_getvar(uint16_t *, struct uuid *, uint32_t *, + u_long *, void *); +efi_status arm_efirt_nextvar(u_long *, uint16_t *, struct uuid *); +efi_status arm_efirt_setvar(uint16_t *, struct uuid *, uint32_t, + u_long, void *); int arm_efirt_reset(enum efi_reset); enum arm_efirt_mem_type { Index: src/sys/arch/arm/fdt/arm_fdt.c diff -u src/sys/arch/arm/fdt/arm_fdt.c:1.19 src/sys/arch/arm/fdt/arm_fdt.c:1.20 --- src/sys/arch/arm/fdt/arm_fdt.c:1.19 Sun Sep 5 13:20:34 2021 +++ src/sys/arch/arm/fdt/arm_fdt.c Sun Oct 10 13:03:09 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: arm_fdt.c,v 1.19 2021/09/05 13:20:34 jmcneill Exp $ */ +/* $NetBSD: arm_fdt.c,v 1.20 2021/10/10 13:03:09 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ #include "opt_modular.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: arm_fdt.c,v 1.19 2021/09/05 13:20:34 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: arm_fdt.c,v 1.20 2021/10/10 13:03:09 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -308,7 +308,7 @@ arm_fdt_efi_init(device_t dev) aprint_debug_dev(dev, "EFI system table at %#" PRIx64 "\n", efi_system_table); - if (arm_efirt_gettime(&tm) == 0) { + if (arm_efirt_gettime(&tm, NULL) == 0) { aprint_normal_dev(dev, "using EFI runtime services for RTC\n"); efi_todr.cookie = NULL; efi_todr.todr_gettime_ymdhms = arm_fdt_efi_rtc_gettime; @@ -321,11 +321,11 @@ static int arm_fdt_efi_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) { struct efi_tm tm; - int error; + efi_status status; - error = arm_efirt_gettime(&tm); - if (error) - return error; + status = arm_efirt_gettime(&tm, NULL); + if (status != 0) + return EIO; dt->dt_year = tm.tm_year; dt->dt_mon = tm.tm_mon; @@ -342,6 +342,7 @@ static int arm_fdt_efi_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) { struct efi_tm tm; + efi_status status; memset(&tm, 0, sizeof(tm)); tm.tm_year = dt->dt_year; @@ -351,6 +352,10 @@ arm_fdt_efi_rtc_settime(todr_chip_handle tm.tm_min = dt->dt_min; tm.tm_sec = dt->dt_sec; - return arm_efirt_settime(&tm); + status = arm_efirt_settime(&tm); + if (status != 0) + return EIO; + + return 0; } #endif Index: src/sys/arch/evbarm/conf/GENERIC64 diff -u src/sys/arch/evbarm/conf/GENERIC64:1.186 src/sys/arch/evbarm/conf/GENERIC64:1.187 --- src/sys/arch/evbarm/conf/GENERIC64:1.186 Thu Sep 23 06:56:27 2021 +++ src/sys/arch/evbarm/conf/GENERIC64 Sun Oct 10 13:03:09 2021 @@ -1,5 +1,5 @@ # -# $NetBSD: GENERIC64,v 1.186 2021/09/23 06:56:27 ryo Exp $ +# $NetBSD: GENERIC64,v 1.187 2021/10/10 13:03:09 jmcneill Exp $ # # GENERIC ARM (aarch64) kernel # @@ -95,6 +95,7 @@ options EXEC_ELF32 # EFI runtime support options EFI_RUNTIME +pseudo-device efi # /dev/efi # Device tree support armfdt0 at root Index: src/sys/conf/majors diff -u src/sys/conf/majors:1.98 src/sys/conf/majors:1.99 --- src/sys/conf/majors:1.98 Sat Jul 24 11:39:19 2021 +++ src/sys/conf/majors Sun Oct 10 13:03:09 2021 @@ -1,4 +1,4 @@ -# $NetBSD: majors,v 1.98 2021/07/24 11:39:19 jmcneill Exp $ +# $NetBSD: majors,v 1.99 2021/10/10 13:03:09 jmcneill Exp $ # # Device majors for Machine-Independent drivers. # @@ -92,3 +92,4 @@ device-major fault char 357 faul device-major wwanc char 358 wwanc device-major acpi char 359 acpi device-major smbios char 360 smbios +device-major efi char 361 efi Index: src/sys/dev/files.dev diff -u src/sys/dev/files.dev:1.7 src/sys/dev/files.dev:1.8 --- src/sys/dev/files.dev:1.7 Wed Jul 21 23:16:09 2021 +++ src/sys/dev/files.dev Sun Oct 10 13:03:09 2021 @@ -1,4 +1,4 @@ -# $NetBSD: files.dev,v 1.7 2021/07/21 23:16:09 jmcneill Exp $ +# $NetBSD: files.dev,v 1.8 2021/10/10 13:03:09 jmcneill Exp $ file dev/bio.c bio needs-flag file dev/ccd.c ccd @@ -27,3 +27,6 @@ file dev/video.c video needs-flag file dev/vnd.c vnd file dev/ipmi.c ipmi needs-flag file dev/smbios.c smbios + +defpseudo efi +file dev/efi.c efi needs-flag Index: src/sys/sys/Makefile diff -u src/sys/sys/Makefile:1.179 src/sys/sys/Makefile:1.180 --- src/sys/sys/Makefile:1.179 Thu Sep 30 01:26:07 2021 +++ src/sys/sys/Makefile Sun Oct 10 13:03:10 2021 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.179 2021/09/30 01:26:07 yamaguchi Exp $ +# $NetBSD: Makefile,v 1.180 2021/10/10 13:03:10 jmcneill Exp $ .include <bsd.own.mk> @@ -18,8 +18,9 @@ INCS= acct.h acl.h agpio.h aio.h ansi.h dir.h dirent.h \ disk.h disklabel.h disklabel_acorn.h disklabel_gpt.h disklabel_rdb.h \ dkbad.h dkio.h dkstat.h domain.h drvctlio.h dvdio.h \ - endian.h envsys.h errno.h evcnt.h event.h eventfd.h exec.h exec_aout.h \ - exec_coff.h exec_ecoff.h exec_elf.h exec_script.h extattr.h extent.h \ + efiio.h endian.h envsys.h errno.h evcnt.h event.h eventfd.h exec.h \ + exec_aout.h exec_coff.h exec_ecoff.h exec_elf.h exec_script.h \ + extattr.h extent.h \ fault.h \ fcntl.h fd_set.h fdio.h featuretest.h file.h filedesc.h filio.h \ flashio.h float_ieee754.h fstypes.h futex.h gcq.h gmon.h gpio.h hash.h \ Added files: Index: src/sys/dev/efi.c diff -u /dev/null src/sys/dev/efi.c:1.1 --- /dev/null Sun Oct 10 13:03:10 2021 +++ src/sys/dev/efi.c Sun Oct 10 13:03:09 2021 @@ -0,0 +1,306 @@ +/* $NetBSD: efi.c,v 1.1 2021/10/10 13:03:09 jmcneill Exp $ */ + +/*- + * Copyright (c) 2021 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * 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. + * 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. + */ + +/* + * This pseudo-driver implements a /dev/efi character device that provides + * ioctls for using UEFI runtime time and variable services. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: efi.c,v 1.1 2021/10/10 13:03:09 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/kmem.h> +#include <sys/atomic.h> +#include <sys/efiio.h> + +#include <dev/efivar.h> + +#ifdef _LP64 +#define EFIERR(x) (0x8000000000000000 | x) +#else +#define EFIERR(x) (0x80000000 | x) +#endif + +#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) + +#include "ioconf.h" + +/* + * Maximum length of an EFI variable name. The UEFI spec doesn't specify a + * constraint, but we want to limit the size to act as a guard rail against + * allocating too much kernel memory. + */ +#define EFI_VARNAME_MAXLENGTH EFI_PAGE_SIZE + +/* + * Pointer to arch specific EFI backend. + */ +static const struct efi_ops *efi_ops = NULL; + +/* + * Only allow one user of /dev/efi at a time. Even though the MD EFI backends + * should serialize individual UEFI RT calls, the UEFI specification says + * that a SetVariable() call between calls to GetNextVariableName() may + * produce unpredictable results, and we want to avoid this. + */ +static u_int efi_isopen = 0; + +static dev_type_open(efi_open); +static dev_type_close(efi_close); +static dev_type_ioctl(efi_ioctl); + +const struct cdevsw efi_cdevsw = { + .d_open = efi_open, + .d_close = efi_close, + .d_ioctl = efi_ioctl, + .d_read = noread, + .d_write = nowrite, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER | D_MPSAFE, +}; + +static int +efi_open(dev_t dev, int flags, int type, struct lwp *l) +{ + if (efi_ops == NULL) { + return ENXIO; + } + if (atomic_cas_uint(&efi_isopen, 0, 1) == 1) { + return EBUSY; + } + return 0; +} + +static int +efi_close(dev_t dev, int flags, int type, struct lwp *l) +{ + KASSERT(efi_isopen); + atomic_swap_uint(&efi_isopen, 0); + return 0; +} + +static int +efi_status_to_error(efi_status status) +{ + switch (status) { + case EFI_SUCCESS: + return 0; + case EFI_INVALID_PARAMETER: + return EINVAL; + case EFI_UNSUPPORTED: + return EOPNOTSUPP; + case EFI_BUFFER_TOO_SMALL: + return ERANGE; + case EFI_DEVICE_ERROR: + return EIO; + case EFI_WRITE_PROTECTED: + return EROFS; + case EFI_OUT_OF_RESOURCES: + return ENOMEM; + case EFI_NOT_FOUND: + return ENOENT; + case EFI_SECURITY_VIOLATION: + return EACCES; + default: + return EIO; + } +} + +static int +efi_ioctl_var_get(struct efi_var_ioc *var) +{ + uint16_t *namebuf; + void *databuf = NULL; + efi_status status; + int error; + + if (var->name == NULL || var->namesize == 0 || + (var->data != NULL && var->datasize == 0)) { + return EINVAL; + } + if (var->namesize > EFI_VARNAME_MAXLENGTH) { + return ENOMEM; + } + + namebuf = kmem_alloc(var->namesize, KM_SLEEP); + error = copyin(var->name, namebuf, var->namesize); + if (error != 0) { + goto done; + } + if (namebuf[var->namesize / 2 - 1] != '\0') { + error = EINVAL; + goto done; + } + if (var->datasize != 0) { + databuf = kmem_alloc(var->datasize, KM_SLEEP); + error = copyin(var->data, databuf, var->datasize); + if (error != 0) { + goto done; + } + } + + status = efi_ops->efi_getvar(namebuf, &var->vendor, &var->attrib, + &var->datasize, databuf); + if (status != EFI_SUCCESS && status != EFI_BUFFER_TOO_SMALL) { + error = efi_status_to_error(status); + goto done; + } + if (status == EFI_SUCCESS && databuf != NULL) { + error = copyout(databuf, var->data, var->datasize); + } else { + var->data = NULL; + } + +done: + kmem_free(namebuf, var->namesize); + if (databuf != NULL) { + kmem_free(databuf, var->datasize); + } + return error; +} + +static int +efi_ioctl_var_next(struct efi_var_ioc *var) +{ + efi_status status; + uint16_t *namebuf; + int error; + + if (var->name == NULL || var->namesize == 0) { + return EINVAL; + } + if (var->namesize > EFI_VARNAME_MAXLENGTH) { + return ENOMEM; + } + + namebuf = kmem_alloc(var->namesize, KM_SLEEP); + error = copyin(var->name, namebuf, var->namesize); + if (error != 0) { + goto done; + } + + status = efi_ops->efi_nextvar(&var->namesize, namebuf, &var->vendor); + if (status != EFI_SUCCESS && status != EFI_BUFFER_TOO_SMALL) { + error = efi_status_to_error(status); + goto done; + } + if (status == EFI_SUCCESS) { + error = copyout(namebuf, var->name, var->namesize); + } else { + var->name = NULL; + } + +done: + kmem_free(namebuf, var->namesize); + return error; +} + +static int +efi_ioctl_var_set(struct efi_var_ioc *var) +{ + efi_status status; + uint16_t *namebuf; + uint16_t *databuf = NULL; + int error; + + if (var->name == NULL || var->namesize == 0) { + return EINVAL; + } + + namebuf = kmem_alloc(var->namesize, KM_SLEEP); + error = copyin(var->name, namebuf, var->namesize); + if (error != 0) { + goto done; + } + if (namebuf[var->namesize / 2 - 1] != '\0') { + error = EINVAL; + goto done; + } + if (var->datasize != 0) { + databuf = kmem_alloc(var->datasize, KM_SLEEP); + error = copyin(var->data, databuf, var->datasize); + if (error != 0) { + goto done; + } + } + + status = efi_ops->efi_setvar(namebuf, &var->vendor, var->attrib, + var->datasize, databuf); + error = efi_status_to_error(status); + +done: + kmem_free(namebuf, var->namesize); + if (databuf != NULL) { + kmem_free(databuf, var->datasize); + } + return error; +} + +static int +efi_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) +{ + KASSERT(efi_ops != NULL); + + switch (cmd) { + case EFIIOC_VAR_GET: + return efi_ioctl_var_get(data); + case EFIIOC_VAR_NEXT: + return efi_ioctl_var_next(data); + case EFIIOC_VAR_SET: + return efi_ioctl_var_set(data); + } + + return ENOTTY; +} + +void +efi_register_ops(const struct efi_ops *ops) +{ + KASSERT(efi_ops == NULL); + efi_ops = ops; +} + +void +efiattach(int count) +{ +} Index: src/sys/dev/efivar.h diff -u /dev/null src/sys/dev/efivar.h:1.1 --- /dev/null Sun Oct 10 13:03:10 2021 +++ src/sys/dev/efivar.h Sun Oct 10 13:03:09 2021 @@ -0,0 +1,46 @@ +/* $NetBSD: efivar.h,v 1.1 2021/10/10 13:03:09 jmcneill Exp $ */ + +/*- + * Copyright (c) 2021 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * 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. + * 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_EFIVAR_H +#define _DEV_EFIVAR_H + +#include <machine/efi.h> + +struct efi_ops { + efi_status (*efi_gettime)(struct efi_tm *, struct efi_tmcap *); + efi_status (*efi_settime)(struct efi_tm *); + efi_status (*efi_getvar)(uint16_t *, struct uuid *, uint32_t *, + u_long *, void *); + efi_status (*efi_setvar)(uint16_t *, struct uuid *, uint32_t, + u_long, void *); + efi_status (*efi_nextvar)(u_long *, uint16_t *, struct uuid *); +}; + +void efi_register_ops(const struct efi_ops *); + +#endif /* !_DEV_EFIVAR_H */ Index: src/sys/sys/efiio.h diff -u /dev/null src/sys/sys/efiio.h:1.1 --- /dev/null Sun Oct 10 13:03:10 2021 +++ src/sys/sys/efiio.h Sun Oct 10 13:03:10 2021 @@ -0,0 +1,64 @@ +/* $NetBSD: efiio.h,v 1.1 2021/10/10 13:03:10 jmcneill Exp $ */ + +/*- + * Copyright (c) 2021 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jared McNeill <jmcne...@invisible.ca>. + * + * 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. + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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 _SYS_EFIIO_H +#define _SYS_EFIIO_H + +#include <sys/types.h> +#include <sys/ioccom.h> +#include <sys/uuid.h> + +/* + * Variable attributes + */ +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 +#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 +#define EFI_VARIABLE_APPEND_WRITE 0x00000040 +#define EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS 0x00000080 + +struct efi_var_ioc { + uint16_t * name; /* vendor's variable name */ + size_t namesize; /* size in bytes of the name buffer */ + struct uuid vendor; /* unique identifier for vendor */ + uint32_t attrib; /* variable attribute bitmask */ + void * data; /* buffer containing variable data */ + size_t datasize; /* size in bytes of the data buffer */ +}; + +#define EFIIOC_VAR_GET _IOWR('E', 4, struct efi_var_ioc) +#define EFIIOC_VAR_NEXT _IOWR('E', 5, struct efi_var_ioc) +#define EFIIOC_VAR_SET _IOWR('E', 7, struct efi_var_ioc) + +#endif /* _SYS_EFIIO_H */