From a915889b7fbbc4be11f9a37ea7afb5b3f3d41173 Mon Sep 17 00:00:00 2001 From: Ge Song Date: Thu, 2 Aug 2018 17:29:36 +0000 Subject: lib/efi: Add new routines to access efi variables Provide methods to load/store petitboot's configuration on efi-based platforms. A test case is also provided. Signed-off-by: Ge Song [Cleanup file comments, make efivarfs_path static.] Signed-off-by: Geoff Levand Signed-off-by: Samuel Mendoza-Jonas --- lib/Makefile.am | 4 +- lib/efi/efivar.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/efi/efivar.h | 46 ++++++++++++++ 3 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 lib/efi/efivar.c create mode 100644 lib/efi/efivar.h (limited to 'lib') diff --git a/lib/Makefile.am b/lib/Makefile.am index 0088e0b..59d37ab 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -65,7 +65,9 @@ lib_libpbcore_la_SOURCES = \ lib/util/util.h \ lib/flash/config.h \ lib/flash/flash.h \ - lib/security/security.h + lib/security/security.h \ + lib/efi/efivar.h \ + lib/efi/efivar.c if ENABLE_MTD lib_libpbcore_la_SOURCES += \ diff --git a/lib/efi/efivar.c b/lib/efi/efivar.c new file mode 100644 index 0000000..1ac6990 --- /dev/null +++ b/lib/efi/efivar.c @@ -0,0 +1,191 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights + * reserved. + * Author: Ge Song + */ + +#include +#include +#include +#include + +#include +#include + +#include "efivar.h" +#include "log/log.h" +#include "talloc/talloc.h" + +static const char *efivarfs_path; + +inline void set_efivarfs_path(const char *path) +{ + efivarfs_path = path; +} + +inline const char *get_efivarfs_path(void) +{ + + return efivarfs_path; +} + +int efi_del_variable(void *ctx, const char *guidstr, + const char *name) +{ + int fd, flag, errno_value; + int rc = -1; + const char *dir; + char *path; + + dir = get_efivarfs_path(); + if (!dir) + return -1; + + path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); + if (!path) + return -1; + + fd = open(path, O_RDONLY|O_NONBLOCK); + if (fd == -1) + goto err; + + rc = ioctl(fd, FS_IOC_GETFLAGS, &flag); + if (rc == -1) + goto err; + + flag &= ~FS_IMMUTABLE_FL; + rc = ioctl(fd, FS_IOC_SETFLAGS, &flag); + if (rc == -1) + goto err; + + close(fd); + rc = unlink(path); + +err: + errno_value = errno; + if (fd > 0) + close(fd); + + errno = errno_value; + return rc; +} + +int efi_get_variable(void *ctx, const char *guidstr, const char *name, + uint8_t **data, size_t *data_size, uint32_t *attributes) +{ + int fd, errno_value; + int rc = -1; + void *p, *buf; + size_t bufsize = 4096; + size_t filesize = 0; + ssize_t sz; + const char *dir; + char *path; + + dir = get_efivarfs_path(); + if (!dir) + return EFAULT; + + path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); + if (!path) + return ENOMEM; + + fd = open(path, O_RDONLY|O_NONBLOCK); + if (fd < 0) + goto err; + + buf = talloc_size(ctx, bufsize); + if (!buf) + goto err; + + do { + p = buf + filesize; + sz = read(fd, p, bufsize); + if (sz < 0 && errno == EAGAIN) { + continue; + } else if (sz == 0) { + break; + } + filesize += sz; + } while (1); + + *attributes = *(uint32_t *)buf; + *data = (uint8_t *)(buf + sizeof(uint32_t)); + *data_size = strlen(buf + sizeof(uint32_t)); + rc = 0; + +err: + errno_value = errno; + if (fd > 0) + close(fd); + + errno = errno_value; + return rc; +} + +int efi_set_variable(void *ctx, const char *guidstr, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes) +{ + int rc = -1, errno_value; + int fd = -1; + ssize_t len; + const char *dir; + char *path; + void *buf; + size_t bufsize; + mode_t mask = 0644; + + dir = get_efivarfs_path(); + if (!dir) + return EFAULT; + + path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); + if (!path) + return ENOMEM; + + if (!access(path, F_OK)) { + rc = efi_del_variable(ctx, guidstr, name); + if (rc < 0) { + goto err; + } + } + + fd = open(path, O_CREAT|O_WRONLY, mask); + if (fd < 0) + goto err; + + bufsize = sizeof(uint32_t) + data_size; + buf = talloc_size(ctx, bufsize); + if (!buf) + goto err; + + *(uint32_t *)buf = attributes; + memcpy(buf + sizeof(uint32_t), data, data_size); + + len = write(fd, buf, bufsize); + if ((size_t)len != bufsize) + goto err; + else + rc = 0; + +err: + errno_value = errno; + if (fd > 0) + close(fd); + + errno = errno_value; + return rc; +} diff --git a/lib/efi/efivar.h b/lib/efi/efivar.h new file mode 100644 index 0000000..ebf73fa --- /dev/null +++ b/lib/efi/efivar.h @@ -0,0 +1,46 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights + * reserved. + * Author: Ge Song + */ +#ifndef EFIVAR_H +#define EFIVAR_H + +#include +#include + +#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 + +#ifndef EFIVARFS_MAGIC +#define EFIVARFS_MAGIC 0xde5e81e4 +#endif + +void set_efivarfs_path(const char *path); +const char *get_efivarfs_path(void); + +int efi_get_variable(void *ctx, const char *guidstr, const char *name, + uint8_t **data, size_t *data_size, uint32_t *attributes); +int efi_set_variable(void *ctx, const char *guidstr, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes); +int efi_del_variable(void *ctx, const char *guidstr, const char *name); + +#endif /* EFIVAR_H */ -- cgit v1.2.1