Message ID | 20180526035359.24024-3-ge.song@hxt-semitech.com |
---|---|
State | Changes Requested |
Headers | show |
Series | Add support for arm64 efi-based platform | expand |
On Sat, 2018-05-26 at 11:53 +0800, Ge Song wrote: > Provide methods to load/store petitboot's configuration on efi-based > platforms. A test case is also provided. > > Signed-off-by: Ge Song <ge.song@hxt-semitech.com> > --- > Since V4: > * test-efivar.c: Use a test directory other than the system's efivarfs to > complete the test for efivar lib. > * lib/efi: Add API to support caller to pass a custom efivarfs path. Looks good! > > > lib/Makefile.am | 2 + > test/lib/Makefile.am | 3 +- > lib/efi/efivar.h | 46 +++++ > lib/efi/efivar.c | 204 ++++++++++++++++++++ > test/lib/test-efivar.c | 127 ++++++++++++ > 5 files changed, 381 insertions(+), 1 deletion(-) > > diff --git a/lib/Makefile.am b/lib/Makefile.am > index 8f682021d45a..cfaa0d2cad47 100644 > --- a/lib/Makefile.am > +++ b/lib/Makefile.am > @@ -59,6 +59,8 @@ lib_libpbcore_la_SOURCES = \ > lib/util/util.h \ > lib/flash/config.h \ > lib/flash/flash.h \ > + lib/efi/efivar.h \ > + lib/efi/efivar.c \ > $(gpg_int_SOURCES) > > if ENABLE_MTD > diff --git a/test/lib/Makefile.am b/test/lib/Makefile.am > index 9636b08d6a6b..22e3ac91499d 100644 > --- a/test/lib/Makefile.am > +++ b/test/lib/Makefile.am > @@ -23,7 +23,8 @@ lib_TESTS = \ > test/lib/test-process-parent-stdout \ > test/lib/test-process-both \ > test/lib/test-process-stdout-eintr \ > - test/lib/test-fold > + test/lib/test-fold \ > + test/lib/test-efivar > > $(lib_TESTS): LIBS += $(core_lib) > > diff --git a/lib/efi/efivar.h b/lib/efi/efivar.h > new file mode 100644 > index 000000000000..058b196e5050 > --- /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 <ge.song@hxt-semitech.com> > + */ > +#ifndef EFIVAR_H > +#define EFIVAR_H > + > +#include <linux/magic.h> > +#include <stdint.h> > + > +#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 > + > +extern const char *efivarfs_path; > + > +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 */ > diff --git a/lib/efi/efivar.c b/lib/efi/efivar.c > new file mode 100644 > index 000000000000..8e6fce820bfb > --- /dev/null > +++ b/lib/efi/efivar.c > @@ -0,0 +1,204 @@ > +/* > + * Methods to manipulation of EFI variables on UEFI-based platforms > + * > + * The library relies on pesudo file system named "efivarfs". This is the > + * new interface to manipulate EFI varibles and was part of the linux > + * kernel v3.10 release. > + * > + * There is also a legacy efivars interface exported via the path > + * "firmware/efi/vars/" relative to the mount point of sysfs. Since it has > + * some drawbacks and is deprecated, we don't support this interface. > + * > + * 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 <ge.song@hxt-semitech.com> > + */ > + > +#include <errno.h> > +#include <fcntl.h> > +#include <linux/fs.h> > +#include <stdbool.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <sys/ioctl.h> > +#include <sys/stat.h> > +#include <sys/types.h> > +#include <unistd.h> > + > +#include "efivar.h" > +#include "talloc/talloc.h" > + > +const char *efivarfs_path = NULL; > + > +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 EFAULT; > + > + path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); > + if (!path) > + return ENOMEM; > + > + 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/test/lib/test-efivar.c b/test/lib/test-efivar.c > new file mode 100644 > index 000000000000..8ceb8f50cae9 > --- /dev/null > +++ b/test/lib/test-efivar.c > @@ -0,0 +1,127 @@ > +/* > + * 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 <ge.song@hxt-semitech.com> > + */ > +#include <assert.h> > +#include <dirent.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <linux/limits.h> > +#include <stdbool.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <sys/stat.h> > +#include <sys/statfs.h> > +#include <unistd.h> > + > +#include "efi/efivar.h" > +#include "talloc/talloc.h" > + > +#define DEF_ATTR (EFI_VARIABLE_NON_VOLATILE | \ > + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS) > + > +static const char *test_efivar_guid = "c9c07add-256e-4452-b911-f8d0d35a1ac7"; > +static const char *test_varname = "efivartest"; > +static const char *test_data = "petitboot"; > + > +static char* find_efitest_path(void) > +{ > + static char dir[PATH_MAX] = {0}; > + static bool run = false; > + char *rest_path = "/efivarfs_data/"; > + char *pos = NULL; > + > + if (run) > + return dir; > + > + readlink("/proc/self/exe", dir, PATH_MAX); > + > + pos = strrchr(dir, '/'); > + *pos = '\0'; > + > + strcat(dir, rest_path); > + run = true; > + > + return dir; > +} > + > +static bool probe(void) > +{ > + char *path; > + int rc; > + > + path = find_efitest_path(); > + > + rc = access(path, F_OK); > + if (rc) { > + if (errno == ENOENT) { > + rc = mkdir(path, 0755); > + if(rc) > + return false; > + } else { > + return false; > + } > + } > + > + set_efivarfs_path(path); > + > + return true; > +} > + > +int main(void) > +{ > + void *ctx = NULL; > + int rc, errno_value; > + size_t size; > + uint8_t *data = NULL; > + uint32_t attr = DEF_ATTR; > + char *path = NULL; > + > + if(!probe()) > + return ENOENT; > + > + talloc_new(ctx); > + size = strlen(test_data) + 1; > + rc = efi_set_variable(ctx, test_efivar_guid, test_varname, > + (uint8_t *)test_data, size, attr); > + > + rc = efi_get_variable(ctx, test_efivar_guid, test_varname, > + &data, &size, &attr); > + > + assert(data != NULL); > + rc = strcmp((char *)data, test_data); > + if (rc) { > + talloc_free(ctx); > + assert(0); > + } > + > + rc = efi_del_variable(ctx, test_efivar_guid, test_varname); > + > + rc = efi_get_variable(ctx, test_efivar_guid, test_varname, > + &data, &size, &attr); > + > + errno_value = errno; > + talloc_free(ctx); > + > + assert(errno_value == ENOENT); > + > + path = find_efitest_path(); > + rmdir(path); > + > + return EXIT_SUCCESS; > +}
Hi Ge, On 05/25/2018 08:53 PM, Ge Song wrote: > +++ b/lib/efi/efivar.h> +#ifndef EFIVAR_H > +#define EFIVAR_H > > +#ifndef EFIVARFS_MAGIC > +#define EFIVARFS_MAGIC 0xde5e81e4 Do we want to be supporting libc so old it does not have EFIVARFS_MAGIC? Maybe emit an error here: #error Upgrade libc to a newer version with EFIVARFS_MAGIC > +#endif > diff --git a/lib/efi/efivar.c b/lib/efi/efivar.c > new file mode 100644 > index 000000000000..8e6fce820bfb > --- /dev/null > +++ b/lib/efi/efivar.c The only use of ctx in the efivar.c functions is to attach temp variables like path and buf. We shouldn't be adding temp variables to contexts. I think it better to not have ctx, then delete any temp variables on function exit. > +#include "talloc/talloc.h" > + > +const char *efivarfs_path = NULL; efivarfs_path is a global, so this initialization is unneeded. It will be initialized to NULL. > + > +inline void set_efivarfs_path(const char *path) > +int efi_get_variable(void *ctx, const char *guidstr, const char *name, > + uint8_t **data, size_t *data_size, uint32_t *attributes) So use int efi_get_variable(const char *guidstr, ...) > +{ > + 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); Use talloc_asprintf(NULL, ...) > + if (!path) > + return ENOMEM; > + > + fd = open(path, O_RDONLY|O_NONBLOCK); > + if (fd < 0) > + goto err; > + > + buf = talloc_size(ctx, bufsize); and talloc_size(path, ...) > + 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: then talloc_free(path) > + errno_value = errno; > + if (fd > 0) > + close(fd); > + > + errno = errno_value; > + return rc; > +}
diff --git a/lib/Makefile.am b/lib/Makefile.am index 8f682021d45a..cfaa0d2cad47 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -59,6 +59,8 @@ lib_libpbcore_la_SOURCES = \ lib/util/util.h \ lib/flash/config.h \ lib/flash/flash.h \ + lib/efi/efivar.h \ + lib/efi/efivar.c \ $(gpg_int_SOURCES) if ENABLE_MTD diff --git a/test/lib/Makefile.am b/test/lib/Makefile.am index 9636b08d6a6b..22e3ac91499d 100644 --- a/test/lib/Makefile.am +++ b/test/lib/Makefile.am @@ -23,7 +23,8 @@ lib_TESTS = \ test/lib/test-process-parent-stdout \ test/lib/test-process-both \ test/lib/test-process-stdout-eintr \ - test/lib/test-fold + test/lib/test-fold \ + test/lib/test-efivar $(lib_TESTS): LIBS += $(core_lib) diff --git a/lib/efi/efivar.h b/lib/efi/efivar.h new file mode 100644 index 000000000000..058b196e5050 --- /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 <ge.song@hxt-semitech.com> + */ +#ifndef EFIVAR_H +#define EFIVAR_H + +#include <linux/magic.h> +#include <stdint.h> + +#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 + +extern const char *efivarfs_path; + +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 */ diff --git a/lib/efi/efivar.c b/lib/efi/efivar.c new file mode 100644 index 000000000000..8e6fce820bfb --- /dev/null +++ b/lib/efi/efivar.c @@ -0,0 +1,204 @@ +/* + * Methods to manipulation of EFI variables on UEFI-based platforms + * + * The library relies on pesudo file system named "efivarfs". This is the + * new interface to manipulate EFI varibles and was part of the linux + * kernel v3.10 release. + * + * There is also a legacy efivars interface exported via the path + * "firmware/efi/vars/" relative to the mount point of sysfs. Since it has + * some drawbacks and is deprecated, we don't support this interface. + * + * 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 <ge.song@hxt-semitech.com> + */ + +#include <errno.h> +#include <fcntl.h> +#include <linux/fs.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "efivar.h" +#include "talloc/talloc.h" + +const char *efivarfs_path = NULL; + +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 EFAULT; + + path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); + if (!path) + return ENOMEM; + + 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/test/lib/test-efivar.c b/test/lib/test-efivar.c new file mode 100644 index 000000000000..8ceb8f50cae9 --- /dev/null +++ b/test/lib/test-efivar.c @@ -0,0 +1,127 @@ +/* + * 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 <ge.song@hxt-semitech.com> + */ +#include <assert.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <linux/limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <unistd.h> + +#include "efi/efivar.h" +#include "talloc/talloc.h" + +#define DEF_ATTR (EFI_VARIABLE_NON_VOLATILE | \ + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS) + +static const char *test_efivar_guid = "c9c07add-256e-4452-b911-f8d0d35a1ac7"; +static const char *test_varname = "efivartest"; +static const char *test_data = "petitboot"; + +static char* find_efitest_path(void) +{ + static char dir[PATH_MAX] = {0}; + static bool run = false; + char *rest_path = "/efivarfs_data/"; + char *pos = NULL; + + if (run) + return dir; + + readlink("/proc/self/exe", dir, PATH_MAX); + + pos = strrchr(dir, '/'); + *pos = '\0'; + + strcat(dir, rest_path); + run = true; + + return dir; +} + +static bool probe(void) +{ + char *path; + int rc; + + path = find_efitest_path(); + + rc = access(path, F_OK); + if (rc) { + if (errno == ENOENT) { + rc = mkdir(path, 0755); + if(rc) + return false; + } else { + return false; + } + } + + set_efivarfs_path(path); + + return true; +} + +int main(void) +{ + void *ctx = NULL; + int rc, errno_value; + size_t size; + uint8_t *data = NULL; + uint32_t attr = DEF_ATTR; + char *path = NULL; + + if(!probe()) + return ENOENT; + + talloc_new(ctx); + size = strlen(test_data) + 1; + rc = efi_set_variable(ctx, test_efivar_guid, test_varname, + (uint8_t *)test_data, size, attr); + + rc = efi_get_variable(ctx, test_efivar_guid, test_varname, + &data, &size, &attr); + + assert(data != NULL); + rc = strcmp((char *)data, test_data); + if (rc) { + talloc_free(ctx); + assert(0); + } + + rc = efi_del_variable(ctx, test_efivar_guid, test_varname); + + rc = efi_get_variable(ctx, test_efivar_guid, test_varname, + &data, &size, &attr); + + errno_value = errno; + talloc_free(ctx); + + assert(errno_value == ENOENT); + + path = find_efitest_path(); + rmdir(path); + + return EXIT_SUCCESS; +}
Provide methods to load/store petitboot's configuration on efi-based platforms. A test case is also provided. Signed-off-by: Ge Song <ge.song@hxt-semitech.com> --- Since V4: * test-efivar.c: Use a test directory other than the system's efivarfs to complete the test for efivar lib. * lib/efi: Add API to support caller to pass a custom efivarfs path. lib/Makefile.am | 2 + test/lib/Makefile.am | 3 +- lib/efi/efivar.h | 46 +++++ lib/efi/efivar.c | 204 ++++++++++++++++++++ test/lib/test-efivar.c | 127 ++++++++++++ 5 files changed, 381 insertions(+), 1 deletion(-)