Index: lib/Makefile =================================================================== --- lib/Makefile +++ lib/Makefile @@ -48,6 +48,7 @@ libdevstat \ libdwarf \ libedit \ + ${_libefivar} \ ${_libelftc} \ libevent \ libexecinfo \ @@ -239,6 +240,10 @@ _libcplusplus= libc++ .endif +.if ${MACHINE_ARCH} == "amd64" +_libefivar= libefivar +.endif + .if ${MK_LIBTHR} != "no" _libthr= libthr .endif Index: lib/libefi/Makefile =================================================================== --- lib/libefi/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# $FreeBSD$ - -.include - -PACKAGE=lib${LIB} -LIB= efi -SHLIB_MAJOR= 1 - -SRCS= libefi.c \ - efi_getvar.c \ - efi_nextvarname.c \ - efi_setvar.c - -CFLAGS+= -I${.CURDIR} - -INCS= libefi.h - -MAN+= libefi.3 -MLINKS+=libefi.3 efi_getvar.3 \ - libefi.3 efi_nextvarname.3 \ - libefi.3 efi_setvar.3 - -.include Index: lib/libefi/efi_getvar.c =================================================================== --- lib/libefi/efi_getvar.c +++ /dev/null @@ -1,68 +0,0 @@ -/*- - * Copyright (c) 2010 Marcel Moolenaar - * 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 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 AUTHOR 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. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include "libefi_int.h" - -/* - * EFI_STATUS - * GetVariable( - * IN CHAR16 *VariableName, - * IN EFI_GUID *VendorGuid, - * OUT UINT32 *Attributes OPTIONAL, - * IN OUT UINTN *DataSize, - * OUT VOID *Data - * ); - */ - -int -efi_getvar(char *name, uuid_t *vendor, uint32_t *attrib, size_t *datasize, - void *data) -{ - struct iodev_efivar_req req; - int error; - - req.namesize = 0; - error = libefi_utf8_to_ucs2(name, &req.namesize, &req.name); - if (error) - return (error); - - req.vendor = *vendor; - req.datasize = *datasize; - req.data = data; - req.access = IODEV_EFIVAR_GETVAR; - error = libefi_efivar(&req); - *datasize = req.datasize; - if (!error && attrib != NULL) - *attrib = req.attrib; - free(req.name); - return (error); -} Index: lib/libefi/efi_nextvarname.c =================================================================== --- lib/libefi/efi_nextvarname.c +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * Copyright (c) 2010 Marcel Moolenaar - * 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 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 AUTHOR 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. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include "libefi_int.h" - -/* - * EFI_STATUS - * GetNextVariableName( - * IN OUT UINTN *VariableNameSize, - * IN OUT CHAR16 *VariableName, - * IN OUT EFI_GUID *VendorGuid - * ); - */ - -int -efi_nextvarname(size_t *namesize, char *name, uuid_t *vendor) -{ - struct iodev_efivar_req req; - int error; - - req.namesize = *namesize; - error = libefi_utf8_to_ucs2(name, &req.namesize, &req.name); - if (error) - return (error); - - req.vendor = *vendor; - req.access = IODEV_EFIVAR_NEXTNAME; - error = libefi_efivar(&req); - *namesize = req.namesize; - if (!error) { - error = libefi_ucs2_to_utf8(req.name, namesize, name); - if (!error) - *vendor = req.vendor; - } - free(req.name); - return (error); -} Index: lib/libefi/libefi.h =================================================================== --- lib/libefi/libefi.h +++ /dev/null @@ -1,57 +0,0 @@ -/*- - * Copyright (c) 2010 Marcel Moolenaar - * 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 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 AUTHOR 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. - * - * $FreeBSD$ - */ - -#ifndef _LIBEFI_H_ -#define _LIBEFI_H_ - -#include -#include -#include - -/* Attributes. */ -#define EFI_ATTR_NV 0x0001 /* Variable stored in NVRAM. */ -#define EFI_ATTR_BS 0x0002 /* Boot services accessable. */ -#define EFI_ATTR_RT 0x0004 /* Runtime accessable. */ -#define EFI_ATTR_HR 0x0008 /* Hardware error record. */ -#define EFI_ATTR_WR 0x0010 /* Authenticated write access. */ - -/* Vendor for architecturally defined variables. */ -#define EFI_GLOBAL_VARIABLE \ - {0x8be4df61,0x93ca,0x11d2,0xaa,0x0d,{0x00,0xe0,0x98,0x03,0x2b,0x8c}} - -/* Vendor for FreeBSD-specific variables. */ -#define EFI_FREEBSD_VARIABLE \ - {0x13c32014,0x0c9c,0x11df,0xa2,0x38,{0x00,0x17,0xa4,0xab,0x91,0x2d}} - -__BEGIN_DECLS -int efi_getvar (char *, uuid_t *, uint32_t *, size_t *, void *); -int efi_nextvarname (size_t *, char *, uuid_t *); -int efi_setvar (char *, uuid_t *, uint32_t, size_t, void *); -__END_DECLS - -#endif /* _LIBEFI_H_ */ Index: lib/libefi/libefi.3 =================================================================== --- lib/libefi/libefi.3 +++ /dev/null @@ -1,143 +0,0 @@ -.\"- -.\" Copyright (c) 2010 Marcel Moolenaar -.\" 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 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 AUTHOR 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. -.\" -.\" $FreeBSD$ -.\" -.Dd January 29, 2010 -.Dt LIBEFI 3 -.Os -.Sh NAME -.Nm efi_getvar , efi_nextvarname , efi_setvar -.Nd "interface for accessing the EFI variable services" -.Sh LIBRARY -.Lb libefi -.Sh SYNOPSIS -.In libefi.h -.Ft int -.Fo efi_getvar -.Fa "char *name" "uuid_t *vendor" "uint32_t *attrib" -.Fa "size_t *datasize" "void *data" -.Fc -.Ft int -.Fn efi_nextvarname "size_t *namesize" "char *name" "uuid_t *vendor" -.Ft int -.Fo efi_setvar -.Fa "char *name" "uuid_t *vendor" "uint32_t attrib" -.Fa "size_t datasize" "void *data" -.Fc -.Sh DESCRIPTION -The -.Nm libefi -library provides access to a select set of the runtime services of the -Extensible Firmware Interface (EFI). -.Pp -The -.Fn efi_nextvarname -function is used to enumerate the variables. -The -.Fa namesize -parameter needs to be set to the size of the buffer pointed to by -.Fa name . -On return, -.Fa namesize -is set to the length of the variable name (including the terminating -.Ql \e0 ) -irrespective of whether the buffer was big enough. -The buffer pointed to by -.Fa name -contains the full or partial variable name on return. -Only on successful completion of the request is the -.Fa vendor -updated. -The values returned should be passed to successive calls to -.Fn efi_nextvarname -until all variables have been enumerated. -.Pp -The variable name and vendor as returned by -.Fn efi_nextvarname -can be passed to -.Fn efi_getvar -to obtain the value and attribute of the variable. -The buffer that is to contain the value is specified by -.Fa data -and the size of the buffer is given by -.Fa datasize . -The attribute pointed to by -.Fa attrib -consists of the bit values defined by the EFI specification. -.Pp -Variables can be created, modified and deleted using the -.Fn efi_setvar -function. -All new variables must be non-volatile and runtime accessible in -order for the request to succeed. -Note that for runtime accessable variables the boottime accessable bit must -be set as well. -To delete a variable, set -.Fa datasize -to 0. -.Pp -The vendor UUID is used to avoid collisions between variable names of -different vendors. -Variables created for use by -.Fx -should use the -.Dv EFI_FREEBSD_VARIABLE -UUID as defined in the -.In libefi.h -header file. -.Sh RETURN VALUES -Upon successful completion, these functions return 0. -Otherwise, the error number is returned. -These functions will fail if: -.Bl -tag -width Er -.It Bq Er EACCES -Insufficient permissions to access the EFI services. -.It Bq Er EILSEQ -The variable name is not in UTF-8. -.It Bq Er EINVAL -The request has invalid parameters. -.It Bq Er ENOENT -The variable does not exist or no more variables exist. -.It Bq Er ENOMEM -Temporary storage could not be allocated. -.It Bq Er EOVERFLOW -The variable name is too long or the data is too big to fit in -the buffer provided. -.El -.Sh SEE ALSO -.Xr errno 2 , -.Xr uuid 3 -.Sh HISTORY -The -.Nm libefi -library first appeared in -.Fx 9.0 -for the ia64 architecture. -.Sh AUTHORS -The -.Nm libefi -library and this manual page were written by -.An Marcel Moolenaar Aq Mt marcel@FreeBSD.org . Index: lib/libefivar/Makefile =================================================================== --- /dev/null +++ lib/libefivar/Makefile @@ -0,0 +1,53 @@ +# Copyright 1998 Juniper Networks, Inc. +# 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 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 AUTHOR 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. +# +# $FreeBSD$ + +.include + +PACKAGE=lib${LIB} +LIB= efivar +SRCS= efivar.c libefivar.c +INCS= efivar.h +SHLIB_MAJOR= 1 +MAN= efivar.3 + +MLINKS+=efivar.3 efi_set_variables_supported.3 \ + efivar.3 efi_del_variable.3 \ + efivar.3 efi_get_variable.3 \ + efivar.3 efi_get_variable_attributes.3 \ + efivar.3 efi_get_variable_size.3 \ + efivar.3 efi_append_variable.3 \ + efivar.3 efi_set_variable.3 \ + efivar.3 efi_get_next_variable_name.3 \ + efivar.3 efi_str_to_guid.3 \ + efivar.3 efi_guid_to_str.3 \ + efivar.3 efi_name_to_guid.3 \ + efivar.3 efi_guid_to_name.3 \ + efivar.3 efi_guid_to_symbol.3 \ + efivar.3 libefivar.3 + +WARNS?= 9 + +.include Index: lib/libefivar/efivar.h =================================================================== --- /dev/null +++ lib/libefivar/efivar.h @@ -0,0 +1,121 @@ +/*- + * Copyright (c) 2016 Netflix, Inc. + * 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 + * 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. + * + * $FreeBSD$ + */ + +#ifndef _EFIVAR_H_ +#define _EFIVAR_H_ + +#include +#include +#include +#include + +/* Shoud these be elsewhere ? */ +#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 +#if 0 /* todo */ +#define EFI_VARIABLE_HAS_AUTH_HEADER +#define EFI_VARIABLE_HAS_SIGNATURE +#endif + + +typedef uuid_t efi_guid_t; +#if BYTE_ORDER == LITTLE_ENDIAN +#define EFI_GUID(a, b, c, d, e0, e1, e2, e3, e4, e5) \ + ((efi_guid_t) {(a), (b), (c), (d) >> 8, (d) & 0xff, \ + { (e0), (e1), (e2), (e3), (e4), (e5) }}) +#else +#define EFI_GUID(a, b, c, d, e0, e1, e2, e3, e4, e5) \ + ((efi_guid_t) {(a), (b), (c), (d) & 0xff, (d) >> 8, \ + { (e0), (e1), (e2), (e3), (e4), (e5) }}) +#endif + +#define EFI_GLOBAL_GUID EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa0d, \ + 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) + +int efi_append_variable(efi_guid_t guid, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes); +int efi_del_variable(efi_guid_t guid, const char *name); +int efi_get_variable(efi_guid_t guid, const char *name, + uint8_t **data, size_t *data_size, uint32_t *attributes); +int efi_get_variable_attributes(efi_guid_t guid, const char *name, + uint32_t *attributes); +int efi_get_variable_size(efi_guid_t guid, const char *name, size_t *size); +int efi_get_next_variable_name(efi_guid_t **guid, char **name); +int efi_guid_cmp(const efi_guid_t *guid1, const efi_guid_t *guid2); +int efi_guid_is_zero(const efi_guid_t *guid1); +int efi_guid_to_name(efi_guid_t *guid, char **name); +int efi_guid_to_symbol(efi_guid_t *guid, char **symbol); +int efi_guid_to_str(const efi_guid_t *guid, char **sp); +int efi_name_to_guid(const char *name, efi_guid_t *guid); +int efi_set_variable(efi_guid_t guid, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode); +int efi_str_to_guid(const char *s, efi_guid_t *guid); +int efi_variables_supported(void); + +extern const efi_guid_t efi_guid_empty; + +/* Stubs that are expected, but aren't really used */ +static inline int +efi_error_get(unsigned int n __unused, char ** const fn __unused, + char ** const func __unused, int *line __unused, + char ** const msg __unused, int *err __unused) +{ + return 0; +} + +static inline int +efi_error_set(const char *fn __unused, const char *func __unused, + int line __unused, int err __unused, const char *fmt __unused, ...) +{ + return 0; +} + +static inline void +efi_error_clear(void) +{ +} + +static inline int +efi_error(const char *fmt __unused, ...) +{ + return 0; +} + +static inline int +efi_error_val(int val __unused, const char *fmt __unused, ...) +{ + return 0; +} + +#endif /* _EFIVAR_H_ */ Index: lib/libefivar/efivar.3 =================================================================== --- /dev/null +++ lib/libefivar/efivar.3 @@ -0,0 +1,98 @@ +.\" Copyright 2016 Netflix, Inc. +.\" 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 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd September 14, 2016 +.Dt LIBEFIVAR 3 +.Os +.Sh NAME +.Nm libefivar +.Nd EFI Non Volatile Variable Suppoert +.Sh SYNOPSIS +.In efivar.h +.Ft int +.Fn efi_append_variable "efi_guid_t guid" "const char *name" "void *data" "size_t data_size" "uint32_t attributes" +.Ft int +.Fn efi_del_variable "efi_guid_t guid" "const char *name" +.Ft int +.Fn efi_get_variable "efi_guid_t guid" "const char *name" "void **data" "ssize_t *data_size" "uint32_t *attributes" +.Ft int +.Fn efi_get_variable_attributes "efi_guid_t guid" "const char *name" "uint32_t *attributes" +.Ft int +.Fn efi_get_variable_size "efi_guid_t guid" "const char *name" "size_t *size" +.Ft int +.Fn efi_get_next_variable_name "efi_guid_t **guid" "char **name" +.Ft int +.Fn efi_guid_to_name "efi_guid_t *guid" "char **name" +.Ft int +.Fn efi_guid_to_symbol "efi_guid_t *guid" "char **symbol" +.Ft int +.Fn efi_guid_to_str "const efi_guid_t *guid" "char **sp" +.Ft int +.Fn efi_name_to_guid "const char *name" "efi_guid_t *guid" +.Ft int +.Fn efi_set_variable "efi_guid_t guid" "const char *name" "void *data" "size_t data_size" "uint32_t attributes" +.Ft int +.Fn efi_str_to_guid "const char *s" "efi_guid_t *guid"; +.Ft int +.Fn efi_variables_supported "void"; +.Sh DESCRIPTION +The +.Nm +library implements access to EFI Variables via the EFI Runtime +Serivces. +All char * strings are converted to 16-bit UTF strings before passing +them to EFI. +.Pp +.Fn efi_variables_supported +returns non-zero if the current machine supports setting of EFI firmware +variables and the kernel support for doing so is present. +Otherwise zero is returned. +.Pp +.Fn efi_del_variable +deletes the EFI variable selected by +.Dv guid +and +.Dv name . +.Pp +.Fn efi_get_variable +.Fn efi_get_variable_attributes +.Fn efi_get_variable_size +.Fn efi_append_variable +.Fn efi_set_variable +.Fn efi_get_next_variable_name +.Fn efi_str_to_guid +.Fn efi_guid_to_str +.Fn efi_name_to_guid +.Fn efi_guid_to_name +.Fn efi_guid_to_symbol +This function is not actually implemented. +.Sh BUGS +No facilities exist to process the strings as native UTF. +This is a limitation in the Linux libefivar library interface. +.Sh AUTHORS +.An -nosplit +This software was originally written by +.An Warner Losh . Index: lib/libefivar/efivar.c =================================================================== --- /dev/null +++ lib/libefivar/efivar.c @@ -0,0 +1,377 @@ +/*- + * Copyright (c) 2016 Netflix, Inc. + * 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 + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libefivar_int.h" + +static int efi_fd = -2; + +#define Z { 0, 0, 0, 0, 0, { 0 } } + +const efi_guid_t efi_guid_empty = Z; + +static struct uuid_table +{ + const char *uuid_str; + const char *name; + efi_guid_t guid; +} guid_tbl [] = +{ + { "00000000-0000-0000-0000-000000000000", "zero", Z }, + { "093e0fae-a6c4-4f50-9f1b-d41e2b89c19a", "sha512", Z }, + { "0abba7dc-e516-4167-bbf5-4d9d1c739416", "redhat", Z }, + { "0b6e5233-a65c-44c9-9407-d9ab83bfc8bd", "sha224", Z }, + { "126a762d-5758-4fca-8531-201a7f57f850", "lenovo_boot_menu", Z }, + { "3bd2a492-96c0-4079-b420-fcf98ef103ed", "x509_sha256", Z }, + { "3c5766e8-269c-4e34-aa14-ed776e85b3b6", "rsa2048", Z }, + { "3CC24E96-22C7-41D8-8863-8E39DCDCC2CF", "lenovo", Z }, + { "3f7e615b-0d45-4f80-88dc-26b234958560", "lenovo_diag", Z }, + { "446dbf63-2502-4cda-bcfa-2465d2b0fe9d", "x509_sha512", Z }, + { "4aafd29d-68df-49ee-8aa9-347d375665a7", "pkcs7_cert", Z }, + { "605dab50-e046-4300-abb6-3dd810dd8b23", "shim", Z }, + { "665d3f60-ad3e-4cad-8e26-db46eee9f1b5", "lenovo_rescue", Z }, + { "67f8444f-8743-48f1-a328-1eaab8736080", "rsa2048_sha1", Z }, + { "7076876e-80c2-4ee6-aad2-28b349a6865b", "x509_sha384", Z }, + { "721c8b66-426c-4e86-8e99-3457c46ab0b9", "lenovo_setup", Z }, + { "77fa9abd-0359-4d32-bd60-28f4e78f784b", "microsoft", Z }, + { "7FACC7B6-127F-4E9C-9C5D-080F98994345", "lenovo_2", Z }, + { "826ca512-cf10-4ac9-b187-be01496631bd", "sha1", Z }, + { "82988420-7467-4490-9059-feb448dd1963", "lenovo_me_config", Z }, + { "8be4df61-93ca-11d2-aa0d-00e098032b8c", "global", Z }, + { "a5c059a1-94e4-4aa7-87b5-ab155c2bf072", "x509_cert", Z }, + { "a7717414-c616-4977-9420-844712a735bf", "rsa2048_sha256_cert", Z }, + { "a7d8d9a6-6ab0-4aeb-ad9d-163e59a7a380", "lenovo_diag_splash", Z }, + { "ade9e48f-9cb8-98e6-31af-b4e6009e2fe3", "redhat_2", Z }, + { "bc7838d2-0f82-4d60-8316-c068ee79d25b", "lenovo_msg", Z }, + { "c1c41626-504c-4092-aca9-41f936934328", "sha256", Z }, + { "c57ad6b7-0515-40a8-9d21-551652854e37", "shell", Z }, + { "d719b2cb-3d3a-4596-a3bc-dad00e67656f", "security", Z }, + { "e2b36190-879b-4a3d-ad8d-f2e7bba32784", "rsa2048_sha256", Z }, + { "ff3e5307-9fd0-48c9-85f1-8ad56c701e01", "sha384", Z }, + { "f46ee6f4-4785-43a3-923d-7f786c3c8479", "lenovo_startup_interrupt", Z }, + { "ffffffff-ffff-ffff-ffff-ffffffffffff", "zzignore-this-guid", Z }, +}; +#undef Z + +static void +efi_guid_tbl_compile(void) +{ + size_t i; + uint32_t status; + + for (i = 0; i < nitems(guid_tbl); i++) { + uuid_from_string(guid_tbl[i].uuid_str, &guid_tbl[i].guid, + &status); + /* all f's is a bad version, so ignore that error */ + if (status != uuid_s_ok && status != uuid_s_bad_version) + fprintf(stderr, "Can't convert %s to a uuid for %s: %d\n", + guid_tbl[i].uuid_str, guid_tbl[i].name, (int)status); + } +} + +static int +efi_open_dev(void) +{ + + if (efi_fd == -2) + efi_fd = open("/dev/efidev", O_RDWR); + if (efi_fd < 0) + efi_fd = -1; + else + efi_guid_tbl_compile(); + return (efi_fd); +} + +static void +efi_var_reset(struct efi_var_ioc *var) +{ + var->name = NULL; + var->namesize = 0; + memset(&var->vendor, 0, sizeof(var->vendor)); + var->attrib = 0; + var->data = NULL; + var->datasize = 0; +} + +static int +rv_to_linux_rv(int rv) +{ + if (rv == 0) + rv = 1; + else if (errno == ENOENT) { + rv = 0; + errno = 0; + } else + rv = -errno; + return (rv); +} + +int +efi_append_variable(efi_guid_t guid, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes) +{ + + return efi_set_variable(guid, name, data, data_size, + attributes | EFI_VARIABLE_APPEND_WRITE, 0); +} + +int +efi_del_variable(efi_guid_t guid, const char *name) +{ + + /* data_size of 0 deletes the variable */ + return efi_set_variable(guid, name, NULL, 0, 0, 0); +} + +int +efi_get_variable(efi_guid_t guid, const char *name, + uint8_t **data, size_t *data_size, uint32_t *attributes) +{ + struct efi_var_ioc var; + int rv; + static uint8_t buf[1024*32]; + + if (efi_open_dev() == -1) + return -1; + + efi_var_reset(&var); + rv = libefi_utf8_to_ucs2(name, &var.name, &var.namesize); + if (rv != 0) + goto errout; + var.vendor = guid; + var.data = buf; + var.datasize = sizeof(buf); + rv = ioctl(efi_fd, EFIIOC_VAR_GET, &var); + if (data_size != NULL) + *data_size = var.datasize; + if (data != NULL) + *data = buf; + if (attributes != NULL) + *attributes = var.attrib; +errout: + free(var.name); + + return rv_to_linux_rv(rv); +} + +int +efi_get_variable_attributes(efi_guid_t guid, const char *name, + uint32_t *attributes) +{ + /* Make sure this construct works -- I think it will fail */ + + return efi_get_variable(guid, name, NULL, NULL, attributes); +} + +int +efi_get_variable_size(efi_guid_t guid, const char *name, + size_t *size) +{ + + /* XXX check to make sure this matches the linux value */ + + *size = 0; + return efi_get_variable(guid, name, NULL, size, NULL); +} + +int +efi_get_next_variable_name(efi_guid_t **guid, char **name) +{ + struct efi_var_ioc var; + int rv; + static efi_char *buf; + static size_t buflen = 256 * sizeof(efi_char); + static efi_guid_t retguid; + size_t size; + + if (efi_open_dev() == -1) + return -1; + + if (buf == NULL) + buf = malloc(buflen); + +again: + efi_var_reset(&var); + var.name = buf; + var.namesize = buflen; + if (*name == NULL) { + *buf = 0; + /* GUID zeroed in var_reset */ + } else { + rv = libefi_utf8_to_ucs2(*name, &var.name, &size); + if (rv != 0) + goto errout; + var.vendor = **guid; + } + rv = ioctl(efi_fd, EFIIOC_VAR_NEXT, &var); + if (rv == 0 && var.name == NULL) { + /* + * oops, too little space. Try again. + */ + void *new = realloc(buf, buflen); + buflen = var.namesize; + if (new == NULL) { + rv = -1; + errno = ENOMEM; + goto done; + } + buf = new; + goto again; + } + + if (rv == 0) { + *name = NULL; /* XXX */ + var.name[var.namesize / sizeof(efi_char)] = 0; /* EFI doesn't NUL terminate */ + rv = libefi_ucs2_to_utf8(var.name, name); + if (rv != 0) + goto errout; + retguid = var.vendor; + *guid = &retguid; + } +errout: + + /* XXX The linux interface expects name to be a static buffer -- fix or leak memory? */ +done: + return (rv_to_linux_rv(rv)); +} + +int +efi_guid_cmp(const efi_guid_t *guid1, const efi_guid_t *guid2) +{ + uint32_t status; + + return uuid_compare(guid1, guid2, &status); +} + +int +efi_guid_is_zero(const efi_guid_t *guid) +{ + uint32_t status; + + return uuid_is_nil(guid, &status); +} + +int +efi_guid_to_name(efi_guid_t *guid, char **name) +{ + size_t i; + uint32_t status; + + for (i = 0; i < nitems(guid_tbl); i++) { + if (uuid_equal(guid, &guid_tbl[i].guid, &status)) { + *name = strdup(guid_tbl[i].name); + return (0); + } + } + return (efi_guid_to_str(guid, name)); +} + +int +efi_guid_to_symbol(efi_guid_t *guid __unused, char **symbol __unused) +{ + + /* + * Unsure what this is used for, efibootmgr doesn't use it. + * Leave unimplemented for now. + */ + return -1; +} + +int +efi_guid_to_str(const efi_guid_t *guid, char **sp) +{ + uint32_t status; + + /* knows efi_guid_t is a typedef of uuid_t */ + uuid_to_string(guid, sp, &status); + + return (status == uuid_s_ok ? 0 : -1); +} + +int +efi_name_to_guid(const char *name, efi_guid_t *guid) +{ + size_t i; + + for (i = 0; i < nitems(guid_tbl); i++) { + if (strcmp(name, guid_tbl[i].name) == 0) { + *guid = guid_tbl[i].guid; + return (0); + } + } + return (efi_str_to_guid(name, guid)); +} + +int +efi_set_variable(efi_guid_t guid, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode __unused) +{ + struct efi_var_ioc var; + int rv; + + if (efi_open_dev() == -1) + return -1; + + efi_var_reset(&var); + rv = libefi_utf8_to_ucs2(name, &var.name, &var.namesize); + if (rv != 0) + goto errout; + var.vendor = guid; + var.data = data; + var.datasize = data_size; + var.attrib = attributes; + rv = ioctl(efi_fd, EFIIOC_VAR_SET, &var); +errout: + free(var.name); + + return rv; +} + +int +efi_str_to_guid(const char *s, efi_guid_t *guid) +{ + uint32_t status; + + /* knows efi_guid_t is a typedef of uuid_t */ + uuid_from_string(s, guid, &status); + + return (status == uuid_s_ok ? 0 : -1); +} + +int +efi_variables_supported(void) +{ + + return efi_open_dev() != -1; +} Index: lib/libefivar/libefivar.c =================================================================== --- lib/libefivar/libefivar.c +++ lib/libefivar/libefivar.c @@ -27,86 +27,105 @@ #include __FBSDID("$FreeBSD$"); -#include #include -#include +#include #include #include #include #include +#include +#include -#include "libefi_int.h" +#include "libefivar_int.h" -static int __iofd = -1; +#include -static void -iodev_fd_close(void) -{ - - close(__iofd); -} - -static int -iodev_fd(int *fd) +/* + * If nm were converted to utf8, what what would strlen + * return on the resulting string? + */ +static size_t +utf8_len_of_ucs2(const efi_char *nm) { + size_t len; + efi_char c; - *fd = __iofd; - if (__iofd != -1) - return (0); - - __iofd = open("/dev/io", O_RDWR); - if (__iofd == -1) - return (errno); + len = 0; + while (*nm) { + c = *nm++; + if (c > 0x7ff) + len += 3; + else if (c > 0x7f) + len += 2; + else + len++; + } - atexit(iodev_fd_close); - *fd = __iofd; - return (0); + return (len); } int -libefi_ucs2_to_utf8(u_short *nm, size_t *szp, char *name) +libefi_ucs2_to_utf8(const efi_char *nm, char **name) { size_t len, sz; - u_short c; + efi_char c; + char *cp; + int freeit = *name == NULL; + sz = utf8_len_of_ucs2(nm) + 1; len = 0; - sz = *szp; + if (*name != NULL) + cp = *name; + else + cp = *name = malloc(sz); + if (*name == NULL) + return (ENOMEM); + while (*nm) { c = *nm++; if (c > 0x7ff) { if (len++ < sz) - *name++ = 0xE0 | (c >> 12); + *cp++ = (char)(0xE0 | (c >> 12)); if (len++ < sz) - *name++ = 0x80 | ((c >> 6) & 0x3f); + *cp++ = (char)(0x80 | ((c >> 6) & 0x3f)); if (len++ < sz) - *name++ = 0x80 | (c & 0x3f); + *cp++ = (char)(0x80 | (c & 0x3f)); } else if (c > 0x7f) { if (len++ < sz) - *name++ = 0xC0 | ((c >> 6) & 0x1f); + *cp++ = (char)(0xC0 | ((c >> 6) & 0x1f)); if (len++ < sz) - *name++ = 0x80 | (c & 0x3f); + *cp++ = (char)(0x80 | (c & 0x3f)); } else { if (len++ < sz) - *name++ = (c & 0x7f); + *cp++ = (char)(c & 0x7f); } } - if (len++ < sz) - *name++ = 0; - *szp = len; - return ((len <= sz) ? 0 : EOVERFLOW); + if (len >= sz) { + /* Absent bugs, we'll never return EOVERFLOW */ + if (freeit) + free(*name); + return (EOVERFLOW); + } + *cp++ = '\0'; + + return (0); } int -libefi_utf8_to_ucs2(char *name, size_t *szp, u_short **nmp) +libefi_utf8_to_ucs2(const char *name, efi_char **nmp, size_t *len) { - u_short *nm; + efi_char *nm; size_t sz; uint32_t ucs4; int c, bytes; + int freeit = *nmp == NULL; - *szp = sz = (*szp == 0) ? strlen(name) * 2 + 2 : *szp; - *nmp = nm = malloc(sz); + sz = strlen(name) * 2 + 2; + if (*nmp == NULL) + *nmp = malloc(sz); + nm = *nmp; + *len = sz; ucs4 = 0; bytes = 0; @@ -119,7 +138,8 @@ if ((c & 0xc0) != 0x80) { /* Initial characters. */ if (bytes != 0) { - free(nm); + if (freeit) + free(nm); return (EILSEQ); } if ((c & 0xf8) == 0xf0) { @@ -141,36 +161,28 @@ ucs4 = (ucs4 << 6) + (c & 0x3f); bytes--; } else if (bytes == 0) { - free(nm); + if (freeit) + free(nm); return (EILSEQ); } } if (bytes == 0) { if (ucs4 > 0xffff) { - free(nm); + if (freeit) + free(nm); return (EILSEQ); } - *nm++ = (u_short)ucs4; + *nm++ = (efi_char)ucs4; sz -= 2; } } if (sz < 2) { - free(nm); + if (freeit) + free(nm); return (EDOOFUS); } + sz -= 2; *nm = 0; + *len -= sz; return (0); } - -int -libefi_efivar(struct iodev_efivar_req *req) -{ - int error, fd; - - error = iodev_fd(&fd); - if (!error) - error = (ioctl(fd, IODEV_EFIVAR, req) == -1) ? errno : 0; - if (!error) - error = req->result; - return (error); -} Index: lib/libefivar/libefivar_int.h =================================================================== --- lib/libefivar/libefivar_int.h +++ lib/libefivar/libefivar_int.h @@ -29,12 +29,7 @@ #ifndef _LIBEFI_INT_H_ #define _LIBEFI_INT_H_ -#include -#include - -int libefi_ucs2_to_utf8(u_short *, size_t *, char *); -int libefi_utf8_to_ucs2(char *, size_t *, u_short **); - -int libefi_efivar(struct iodev_efivar_req *); +int libefi_ucs2_to_utf8(const efi_char *, char **); +int libefi_utf8_to_ucs2(const char *, efi_char **, size_t *); #endif /* _LIBEFI_INT_H_ */ Index: share/mk/bsd.libnames.mk =================================================================== --- share/mk/bsd.libnames.mk +++ share/mk/bsd.libnames.mk @@ -59,6 +59,7 @@ LIBDTRACE?= ${DESTDIR}${LIBDIR}/libdtrace.a LIBDWARF?= ${DESTDIR}${LIBDIR}/libdwarf.a LIBEDIT?= ${DESTDIR}${LIBDIR}/libedit.a +LIBEFIVAR?= ${DESTDIR}${LIBDIR}/libefivar.a LIBELF?= ${DESTDIR}${LIBDIR}/libelf.a LIBEXECINFO?= ${DESTDIR}${LIBDIR}/libexecinfo.a LIBFETCH?= ${DESTDIR}${LIBDIR}/libfetch.a Index: share/mk/src.libnames.mk =================================================================== --- share/mk/src.libnames.mk +++ share/mk/src.libnames.mk @@ -91,6 +91,7 @@ dtrace \ dwarf \ edit \ + efivar \ elf \ execinfo \ fetch \ Index: share/mk/src.opts.mk =================================================================== --- share/mk/src.opts.mk +++ share/mk/src.opts.mk @@ -82,6 +82,7 @@ DYNAMICROOT \ ED_CRYPTO \ EE \ + EFI \ ELFCOPY_AS_OBJCOPY \ ELFTOOLCHAIN_BOOTSTRAP \ EXAMPLES \ @@ -264,6 +265,9 @@ .if ${__T:Mmips*} BROKEN_OPTIONS+=SSP .endif +.if ${__T:Mmips*} || ${__T:Mpowerpc*} || ${__T:Msparc64} || ${__T:Mriscv*} +BROKEN_OPTIONS+=EFI +.endif .include Index: sys/amd64/amd64/efirt.c =================================================================== --- sys/amd64/amd64/efirt.c +++ sys/amd64/amd64/efirt.c @@ -419,6 +419,13 @@ } int +efi_rt_avail(void) +{ + + return (efi_runtime != 0); +} + +int efi_get_table(struct uuid *uuid, void **ptr) { struct efi_cfgtbl *ct; Index: sys/amd64/conf/GENERIC.efi =================================================================== --- /dev/null +++ sys/amd64/conf/GENERIC.efi @@ -0,0 +1,3 @@ +include GENERIC +device efirt +# device efidev Index: sys/amd64/include/efi.h =================================================================== --- sys/amd64/include/efi.h +++ sys/amd64/include/efi.h @@ -47,6 +47,7 @@ int efi_get_time(struct efi_tm *tm); int efi_get_time_locked(struct efi_tm *tm); int efi_reset_system(void); +int efi_rt_avail(void); int efi_set_time(struct efi_tm *tm); int efi_set_time_locked(struct efi_tm *tm); int efi_var_get(uint16_t *name, struct uuid *vendor, uint32_t *attrib, Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -1430,6 +1430,7 @@ dev/ed/if_ed_rtl80x9.c optional ed dev/ed/if_ed_pccard.c optional ed pccard dev/ed/if_ed_pci.c optional ed pci +dev/efidev/efidev.c optional efidev dev/eisa/eisa_if.m standard dev/eisa/eisaconf.c optional eisa dev/e1000/if_em.c optional em \ Index: sys/dev/efidev/efidev.c =================================================================== --- /dev/null +++ sys/dev/efidev/efidev.c @@ -0,0 +1,268 @@ +/*- + * Copyright (c) 2016 Netflix, Inc. + * 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 + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static d_ioctl_t efidev_ioctl; + +static struct cdevsw efi_cdevsw = { + .d_name = "efi", + .d_version = D_VERSION, + .d_ioctl = efidev_ioctl, +}; + +/* ARGSUSED */ +static int +efidev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, + int flags __unused, struct thread *td __unused) +{ + int error; + + switch (cmd) { + case EFIIOC_GET_TABLE: + { + struct efi_get_table_ioc *egtioc = + (struct efi_get_table_ioc *)addr; + + error = efi_get_table(&egtioc->uuid, &egtioc->ptr); + break; + } + case EFIIOC_GET_TIME: + { + struct efi_tm *tm = (struct efi_tm *)addr; + + error = efi_get_time(tm); + break; + } + case EFIIOC_SET_TIME: + { + struct efi_tm *tm = (struct efi_tm *)addr; + + error = efi_set_time(tm); + break; + } + case EFIIOC_VAR_GET: + { + struct efi_var_ioc *ev = (struct efi_var_ioc *)addr; + void *data = NULL; + efi_char *name = NULL; + + data = malloc(ev->datasize, M_TEMP, M_WAITOK); + if (data == NULL) { + error = ENOMEM; + goto vg_out; + } + name = malloc(ev->namesize, M_TEMP, M_WAITOK); + if (name == NULL) { + error = ENOMEM; + goto vg_out; + } + error = copyin(ev->name, name, ev->namesize); + if (error) + goto vg_out; + if (name[ev->namesize / sizeof(efi_char)] != 0) { + error = EINVAL; + goto vg_out; + } + + error = efi_var_get(name, &ev->vendor, &ev->attrib, + &ev->datasize, data); + + if (error == 0) { + error = copyout(data, ev->data, ev->datasize); + } else if (error == EOVERFLOW) { + /* + * Pass back the size we really need, but + * convert the error to 0 so the copyout + * happens. datasize was updated in the + * efi_var_get call. + */ + ev->data = NULL; + error = 0; + } + vg_out: + if (data != NULL) + free(data, M_TEMP); + if (name != NULL) + free(name, M_TEMP); + break; + } + case EFIIOC_VAR_NEXT: + { + struct efi_var_ioc *ev = (struct efi_var_ioc *)addr; + efi_char *name = NULL; + + name = malloc(ev->namesize, M_TEMP, M_WAITOK); + if (name == NULL) { + error = ENOMEM; + goto vn_out; + } + error = copyin(ev->name, name, ev->namesize); + if (error) + goto vn_out; + /* Note: namesize is the buffer size, not the string lenght */ + + error = efi_var_nextname(&ev->namesize, name, &ev->vendor); + if (error == 0) { + error = copyout(name, ev->name, ev->namesize); + } else if (error == EOVERFLOW) { + ev->name = NULL; + error = 0; + } + vn_out: + if (name != NULL) + free(name, M_TEMP); + break; + } + case EFIIOC_VAR_SET: + { + struct efi_var_ioc *ev = (struct efi_var_ioc *)addr; + void *data = NULL; + efi_char *name = NULL; + + /* datasize == 0 -> delete (more or less) */ + if (ev->datasize > 0) { + data = malloc(ev->datasize, M_TEMP, M_WAITOK); + if (data == NULL) { + error = ENOMEM; + goto vs_out; + } + } + name = malloc(ev->namesize, M_TEMP, M_WAITOK); + if (name == NULL) { + error = ENOMEM; + goto vs_out; + } + if (ev->datasize) { + error = copyin(ev->data, data, ev->datasize); + if (error) + goto vs_out; + } + error = copyin(ev->name, name, ev->namesize); + if (error) + goto vs_out; + if (name[ev->namesize / sizeof(efi_char)] != 0) { + error = EINVAL; + goto vg_out; + } + + error = efi_var_set(name, &ev->vendor, ev->attrib, ev->datasize, + data); + vs_out: + if (data != NULL) + free(data, M_TEMP); + if (name != NULL) + free(name, M_TEMP); + break; + } + default: + error = ENOTTY; + break; + } + + return (error); +} + +struct efidev_softc +{ + struct cdev *cdev; +}; + +static void +efidev_identify(driver_t * driver, device_t parent) +{ + device_t child; + + child = device_find_child(parent, driver->name, 0); + if (child == NULL) + child = BUS_ADD_CHILD(parent, 0, "efidev", -1); + device_set_driver(child, driver); +} + +static int +efidev_probe(device_t dev) +{ + if (!efi_rt_avail()) + return (ENXIO); + + device_set_desc(dev, "efi runtime services"); + return (0); +} + +static int +efidev_attach(device_t dev) +{ + struct efidev_softc *sc; + + sc = device_get_softc(dev); + sc->cdev = make_dev(&efi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0700, + "efidev"); + + return (0); +} +static int +efidev_detach(device_t dev) +{ + struct efidev_softc *sc; + + sc = device_get_softc(dev); + destroy_dev(sc->cdev); + + return (0); +} + +static device_method_t efidev_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, efidev_identify), + DEVMETHOD(device_probe, efidev_probe), + DEVMETHOD(device_attach, efidev_attach), + DEVMETHOD(device_detach, efidev_detach), + + DEVMETHOD_END +}; + +static driver_t efidev_driver = { + "efidev", + efidev_methods, + sizeof(struct efidev_softc), +}; + +static devclass_t efidev_devclass; +DRIVER_MODULE(efidev, nexus, efidev_driver, efidev_devclass, NULL, NULL); +MODULE_VERSION(efidev, 1); Index: sys/i386/include/efi.h =================================================================== --- sys/i386/include/efi.h +++ sys/i386/include/efi.h @@ -1,7 +1,10 @@ /*- - * Copyright (c) 2010 Marcel Moolenaar + * Copyright (c) 2016 The FreeBSD Foundation * All rights reserved. * + * This software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -14,7 +17,7 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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) @@ -22,45 +25,15 @@ * 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. + * + * $FreeBSD$ */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include "libefi_int.h" - -/* - * EFI_STATUS - * SetVariable( - * IN CHAR16 *VariableName, - * IN EFI_GUID *VendorGuid, - * IN UINT32 Attributes, - * IN UINTN DataSize, - * IN VOID *Data - * ); - */ +#ifndef __I386_INCLUDE_EFI_H_ +#define __I386_INCLUDE_EFI_H_ -int -efi_setvar(char *name, uuid_t *vendor, uint32_t attrib, size_t datasize, - void *data) -{ - struct iodev_efivar_req req; - int error; +#define EFIABI_ATTR - req.namesize = 0; - error = libefi_utf8_to_ucs2(name, &req.namesize, &req.name); - if (error) - return (error); +/* Note: we don't actually support this on i386 yet */ - req.vendor = *vendor; - req.attrib = attrib; - req.datasize = datasize; - req.data = data; - req.access = IODEV_EFIVAR_SETVAR; - error = libefi_efivar(&req); - free(req.name); - return (error); -} +#endif /* __I386_INCLUDE_EFI_H_ */ Index: sys/modules/Makefile =================================================================== --- sys/modules/Makefile +++ sys/modules/Makefile @@ -103,6 +103,7 @@ ${_drm2} \ dummynet \ ${_ed} \ + ${_efidev} \ ${_efirt} \ ${_elink} \ ${_em} \ @@ -672,6 +673,7 @@ .endif .if ${MACHINE_CPUARCH} == "amd64" +_efidev= efidev _efirt= efirt _ioat= ioat _ixl= ixl Index: sys/modules/efidev/Makefile =================================================================== --- /dev/null +++ sys/modules/efidev/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/efidev + +KMOD = efidev +SRCS = efidev.c +SRCS += bus_if.h device_if.h + +.include Index: sys/sys/efiio.h =================================================================== --- /dev/null +++ sys/sys/efiio.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2016 Netflix, Inc. + * 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 + * 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. + * + * $FreeBSD$ + */ + +#ifndef _SYS_EFIIO_H_ +#define _SYS_EFIIO_H_ + +#include +#include +#include + +struct efi_get_table_ioc +{ + struct uuid uuid; /* UUID to look up */ + void *ptr; /* Pointer to table in KVA space */ +}; + +struct efi_var_ioc +{ + efi_char *name; /* User pointer to name, in wide chars */ + size_t namesize; /* Number of wide characters in name */ + struct uuid vendor; /* Vendor's UUID for variable */ + uint32_t attrib; /* Attributes */ + void *data; /* User pointer to the data */ + size_t datasize; /* Number of *bytes* in the data */ +}; + +#define EFIIOC_GET_TABLE _IOWR('E', 1, struct efi_get_table_ioc) +#define EFIIOC_GET_TIME _IOR('E', 2, struct efi_tm) +#define EFIIOC_SET_TIME _IOW('E', 3, struct efi_tm) +#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', 6, struct efi_var_ioc) + +#endif /* _SYS_EFIIO_H_ */ Index: usr.sbin/Makefile =================================================================== --- usr.sbin/Makefile +++ usr.sbin/Makefile @@ -123,6 +123,7 @@ SUBDIR.${MK_CTM}+= ctm SUBDIR.${MK_DIALOG}+= tzsetup SUBDIR.${MK_DIALOG}+= bsdconfig +SUBDIR.${MK_EFI}+= efivar SUBDIR.${MK_FLOPPY}+= fdcontrol SUBDIR.${MK_FLOPPY}+= fdformat SUBDIR.${MK_FLOPPY}+= fdread Index: usr.sbin/efivar/Makefile =================================================================== --- /dev/null +++ usr.sbin/efivar/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG= efivar +MAN= efivar.8 + +LIBADD= efivar + +.include Index: usr.sbin/efivar/efivar.8 =================================================================== --- /dev/null +++ usr.sbin/efivar/efivar.8 @@ -0,0 +1,164 @@ +.\" Copyright (c) 2003 Netflix, Inc +.\" 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 REGENTS 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 REGENTS 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. +.\" +.\" $FreeBSD$ +.\" +.Dd September 29, 2016 +.Dt EFIVAR 8 +.Os +.Sh NAME +.Nm efivar +.Nd UEFI environemnt variable interaction +.Sh SYNOPSIS +.Nm +.Op Fl abdDHlLNpRtw +.Op Fl n Ar name +.Op Fl f Ar file +.Op Fl -append +.Op Fl -ascii +.Op Fl -attributes +.Op Fl -binary +.Op Fl -delete +.Op Fl -fromfile Ar file +.Op Fl -hex +.Op Fl -list-guids +.Op Fl -list +.Op Fl -name Ar name +.Op Fl -no-name +.Op Fl -print +.Op Fl -print-decimal +.Op Fl -raw-guid +.Op Fl -write +.Ar name Ns Op = Ns Ar value +.Sh DESCRIPTION +This program manages +.Dq Unified Extensible Firmware Interface +.Pq UEFI +environment variables. +UEFI variables have three part: A namespace, a name and a value. +The namespace is a GUID that's self assigned by the group defining the +variables. +The name is a Unicode name for the variable. +The value is binary data. +All Unicode data is presented to the user as UTF-8. +.Pp +The following options are available: +.Bl -tag -width 20m +.It Fl n Ar name Fl -name Ar name +Specify the name of the variable to operate on. +The +.Ar name +argument is the GUID of variable, followed by a dash, followed by the +UEFI variable name. +The GUID may be in numeric format, or may be one of the well known +symbolic name (see +.Fl -list-guids +for a complete list). +.It Fl f Ar file Fl -fromfile Ar file +When writing or appending to a variable, take the data for the +variable's value from +.Ar file +instead of from the command line. +This flag implies +.Fl -write +unless the +.Fl -append +flag is given. +This is not well understood and currently unimplemented. +.It Fl a Fl -append +Append the specified value to the UEFI variable rather than replacing +it.p +.It Fl t Ar attr Fl -attributes Ar attr +Specify, in user hostile hexidecimal, the attributes for this +variable. +See section 7.2 (GetVariable subsection, Related Definitions) of the +UEFI Specification for hex values to use. +.It Fl A Fl -ascii +Display the variable data as modified ascii: All printable characters +are printed, while unprintable characters are rendered as a two-digit +hexadecimal number preceeded by a % character. +.It Fl A Fl -binary +Display the variable data as binary data. +Usually will be used with the +.Fl N +or +.Fl -no-name +flag. +Useful in scripts. +.It Fl D Fl -delete +Delete the specified variable. +May not be used with either the +.Fl -write +or the +.Fl -append +flags. +No +.Ar value +may be specified. +.It Fl H Fl -hex +List variable data as a hex dump. +.It Fl L Fl -list-guids +Lists the well known GUIDs. +The names listed here may be used in place of the numeric GUID values. +These names will replace the numeric GUID values unless +.Fl -raw-guid +flag is specified. +.It Fl l Fl -list +List all the variables. +If the +.Fl -print +flag is also listed, their values will be displayed. +.It Fl N Fl -no-name +Do not display the variable name. +.It Fl p Fl -print +Print the value of the variable. +.It Fl d Fl -print-decimal +Treat the value of the variable as a number and print it as a +decimal. +This is currently unimplemented. +.It Fl R Fl -raw-guid +Do not substitute well known names for GUID numeric values in output. +.It Fl w Fl -write +Write (replace) the variable specified with the value specified. +.It Ar name +Display the +.Ar name +environment variable. +.It Ar name Ns = Ns Ar value +Set the specified +.Ar name +to +.Ar value . +This is not yet implemented. +.Sh COMPATIBILITY +The +.Nm +program is intended to be compatible (strict superset) with a progam +of the same name included in the Red Hat libefivar package. +.Sh SEE ALSO +Appendix A of the UEFI specification has the format for GUIDs. +All GUIDs +.Dq Globally Unique Identifiers +have the format described in RFC 4122. +.El Index: usr.sbin/efivar/efivar.c =================================================================== --- /dev/null +++ usr.sbin/efivar/efivar.c @@ -0,0 +1,349 @@ +/*- + * Copyright (c) 2016 Netflix, Inc. + * 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 NETAPP, INC ``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 NETAPP, INC 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. + */ + +#include +__FBSDID("$FreeBSD"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* options descriptor */ +static struct option longopts[] = { + { "append", no_argument, NULL, 'a' }, + { "ascii", no_argument, NULL, 'A' }, + { "attributes", required_argument, NULL, 't' }, + { "binary", no_argument, NULL, 'b' }, + { "delete", no_argument, NULL, 'D' }, + { "fromfile", required_argument, NULL, 'f' }, + { "hex", no_argument, NULL, 'H' }, + { "list-guids", no_argument, NULL, 'L' }, + { "list", no_argument, NULL, 'l' }, + { "name", required_argument, NULL, 'n' }, + { "no-name", no_argument, NULL, 'N' }, + { "print", no_argument, NULL, 'p' }, + { "print-decimal", no_argument, NULL, 'd' }, + { "raw-guid", no_argument, NULL, 'R' }, + { "write", no_argument, NULL, 'w' }, + { NULL, 0, NULL, 0 } +}; + + +static int aflag, Aflag, bflag, dflag, Dflag, Hflag, Nflag, + lflag, Lflag, Rflag, wflag, pflag; +static char *varname; +static u_long attrib = 0x7; + +static void +usage(void) +{ + + errx(1, "efivar [-abdDHlLNpRtw] [-n name] [-f file] [--append] [--ascii]\n" + "\t[--attributes] [--binary] [--delete] [--fromfile file] [--hex]\n" + "\t[--list-guids] [--list] [--name name] [--no-name] [--print]\n" + "\t[--print-decimal] [--raw-guid] [--write] name[=value]"); +} + +static void +breakdown_name(char *name, efi_guid_t *guid, char **vname) +{ + char *cp; + + cp = strrchr(name, '-'); + if (cp == NULL) + errx(1, "Invalid name: %s", name); + *vname = cp + 1; + *cp = '\0'; + if (efi_str_to_guid(name, guid) < 0) + errx(1, "Invalid guid %s", name); +} + +static uint8_t * +get_value(char *val, size_t *datalen) +{ + static char buffer[16*1024]; + + if (val != NULL) { + *datalen = strlen(val); + return ((uint8_t *)val); + } + /* Read from stdin */ + *datalen = sizeof(buffer); + *datalen = read(0, buffer, *datalen); + return ((uint8_t *)buffer); +} + +static void +append_variable(char *name, char *val) +{ + char *vname; + efi_guid_t guid; + size_t datalen; + uint8_t *data; + + breakdown_name(name, &guid, &vname); + data = get_value(val, &datalen); + if (efi_append_variable(guid, vname, data, datalen, attrib) < 0) + err(1, "efi_append_variable"); +} + +static void +delete_variable(char *name) +{ + char *vname; + efi_guid_t guid; + + breakdown_name(name, &guid, &vname); + if (efi_del_variable(guid, vname) < 0) + err(1, "efi_del_variable"); +} + +static void +write_variable(char *name, char *val) +{ + char *vname; + efi_guid_t guid; + size_t datalen; + uint8_t *data; + + breakdown_name(name, &guid, &vname); + data = get_value(val, &datalen); + if (efi_set_variable(guid, vname, data, datalen, attrib, 0) < 0) + err(1, "efi_set_variable"); +} + +static void +asciidump(uint8_t *data, size_t datalen) +{ + size_t i; + int len; + + len = 0; + if (!Nflag) + printf("\n"); + for (i = 0; i < datalen; i++) { + if (isprint(data[i])) { + len++; + if (len > 80) { + len = 0; + printf("\n"); + } + printf("%c", data[i]); + } else { + len +=3; + if (len > 80) { + len = 0; + printf("\n"); + } + printf("%%%02x", data[i]); + } + } + printf("\n"); +} + +static void +hexdump(uint8_t *data, size_t datalen) +{ + size_t i; + + if (!Nflag) + printf("\n"); + for (i = 0; i < datalen; i++) { + if (i % 16 == 0) { + if (i != 0) + printf("\n"); + printf("%04x: ", (int)i); + } + printf("%02x ", data[i]); + } + printf("\n"); +} + +static void +bindump(uint8_t *data, size_t datalen) +{ + write(1, data, datalen); +} + +static void +print_var(efi_guid_t *guid, char *name) +{ + uint32_t att; + uint8_t *data; + size_t datalen; + char *gname; + int rv; + + efi_guid_to_str(guid, &gname); + if (!Nflag) + printf("%s-%s", gname, name); + if (pflag) { + rv = efi_get_variable(*guid, name, &data, &datalen, &att); + + if (rv < 0) + printf("\n --- Error getting value --- %d", errno); + else { + if (Aflag) + asciidump(data, datalen); + else if (bflag) + bindump(data, datalen); + else + hexdump(data, datalen); + } + } + free(gname); + if (!Nflag) + printf("\n"); +} + +static void +print_variable(char *name) +{ + char *vname; + efi_guid_t guid; + + breakdown_name(name, &guid, &vname); + print_var(&guid, vname); +} + +static void +print_variables(void) +{ + int rv; + char *name = NULL; + efi_guid_t *guid = NULL; + + while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) + print_var(guid, name); + + if (rv < 0) + err(1, "Error listing names"); +} + +static void +parse_args(int argc, char **argv) +{ + int ch, i; + + while ((ch = getopt_long(argc, argv, "aAbdDf:HlLNn:pRt:w", + longopts, NULL)) != -1) { + switch (ch) { + case 'a': + aflag++; + break; + case 'A': + Aflag++; + break; + case 'b': + bflag++; + break; + case 'd': + dflag++; + break; + case 'D': + Dflag++; + break; + case 'H': + Hflag++; + break; + case 'l': + lflag++; + break; + case 'L': + Lflag++; + break; + case 'n': + varname = optarg; + break; + case 'N': + Nflag++; + break; + case 'p': + pflag++; + break; + case 'R': + Rflag++; + break; + case 'w': + wflag++; + break; + case 'f': + case 't': + case 0: + errx(1, "unknown or unimplemented option\n"); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc == 1) + varname = argv[0]; + + if (aflag + Dflag + wflag > 1) { + warnx("Can only use one of -a (--append), " + "-D (--delete) and -w (--write)"); + usage(); + } + + if (aflag + Dflag + wflag > 0 && varname == NULL) { + warnx("Must specify a variable for -a (--append), " + "-D (--delete) or -w (--write)"); + usage(); + } + + if (aflag) + append_variable(varname, NULL); + else if (Dflag) + delete_variable(varname); + else if (wflag) + write_variable(varname, NULL); + else if (varname) { + pflag++; + print_variable(varname); + } else if (argc > 0) { + pflag++; + for (i = 0; i < argc; i++) + print_variable(argv[i]); + } else + print_variables(); +} + +int +main(int argc, char **argv) +{ + + parse_args(argc, argv); +}