@@ -61,6 +61,10 @@ config HAVE_LIBEBGENV
bool
option env="HAVE_LIBEBGENV"
+config HAVE_LIBTEGRABOOT_TOOLS
+ bool
+ option env="HAVE_LIBTEGRABOOT_TOOLS"
+
config HAVE_LIBEXT2FS
bool
option env="HAVE_LIBEXT2FS"
@@ -50,6 +50,10 @@ ifeq ($(HAVE_LIBEBGENV),)
export HAVE_LIBEBGENV = y
endif
+ifeq ($(HAVE_LIBTEGRABOOT_TOOLS),)
+export HAVE_LIBTEGRABOOT_TOOLS = y
+endif
+
ifeq ($(HAVE_LIBZEROMQ),)
export HAVE_LIBZEROMQ = y
endif
@@ -225,6 +225,9 @@ endif
ifeq ($(CONFIG_BOOTLOADER_EBG),y)
LDLIBS += ebgenv
endif
+ifeq ($(CONFIG_BOOTLOADER_CBOOT),y)
+LDLIBS += tegra-boot-tools
+endif
else
ifeq ($(CONFIG_UBOOT),y)
LDLIBS += dl
@@ -232,6 +235,9 @@ endif
ifeq ($(CONFIG_BOOTLOADER_EBG),y)
LDLIBS += dl
endif
+ifeq ($(CONFIG_BOOTLOADER_CBOOT),y)
+LDLIBS += dl
+endif
endif
ifeq ($(CONFIG_SYSTEMD),y)
@@ -246,6 +252,8 @@ else ifeq ($(CONFIG_BOOTLOADER_DEFAULT_UBOOT),y)
KBUILD_CPPFLAGS += -DBOOTLOADER_DEFAULT="uboot"
else ifeq ($(CONFIG_BOOTLOADER_DEFAULT_EBG),y)
KBUILD_CPPFLAGS += -DBOOTLOADER_DEFAULT="ebg"
+else ifeq ($(CONFIG_BOOTLOADER_DEFAULT_CBOOT),y)
+KBUILD_CPPFLAGS += -DBOOTLOADER_DEFAULT="cboot"
else
KBUILD_CPPFLAGS += -DBOOTLOADER_DEFAULT="none"
endif
@@ -63,6 +63,19 @@ config GRUBENV_PATH
help
Provide path to GRUB environment block file
+config BOOTLOADER_CBOOT
+ bool "NVIDIA Tegra Cboot"
+ depends on HAVE_LIBTEGRABOOT_TOOLS
+ help
+ Support for NVIDIA's cboot used on some Tegra platform. Tegra
+ uses different bootloader, depending on the SOC and on the release
+ provided by vendor. Some SOCs (associated with some releases) are still
+ using U-Boot (Jetson Nano, TX, TX2), some of them are using Cboot (Xavier),
+ and some of them rely on UEFI. This adds support for cboot.
+
+comment "Cboot needs libtegra-boot-tools"
+ depends on !HAVE_LIBTEGRABOOT_TOOLS
+
endmenu
choice
@@ -98,6 +111,12 @@ config BOOTLOADER_DEFAULT_GRUB
help
Use GRUB as default bootloader interface.
+config BOOTLOADER_DEFAULT_CBOOT
+ bool "Cboot"
+ depends on BOOTLOADER_CBOOT
+ help
+ Use NVIDIA Cboot as default bootloader interface.
+
config BOOTLOADER_DEFAULT_NONE
bool "Environment in RAM"
depends on BOOTLOADER_NONE
@@ -6,6 +6,7 @@ obj-$(CONFIG_UBOOT) += uboot.o
obj-$(CONFIG_BOOTLOADER_NONE) += none.o
obj-$(CONFIG_BOOTLOADER_GRUB) += grub.o
obj-$(CONFIG_BOOTLOADER_EBG) += ebg.o
+obj-$(CONFIG_BOOTLOADER_CBOOT) += cboot.o
# Make sure none.o is compiled-in as fallback.
ifeq ($(CONFIG_UBOOT),)
new file mode 100644
@@ -0,0 +1,197 @@
+/*
+ * (C) Copyright 2023 Stefano Babic, stefano.babic@swupdate.org
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+/*
+ * This uses the API of the libtegra-boot-tools library
+ * see info on https://github.com/OE4T/tegra-boot-tools
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "generated/autoconf.h"
+#include "util.h"
+#include "dlfcn.h"
+#include "bootloader.h"
+
+/*
+ * thes edefines are not exported by the library
+ */
+#define BOOTINFO_O_RDONLY (0<<0)
+#define BOOTINFO_O_RDWR (3<<0)
+#define BOOTINFO_O_CREAT (1<<2)
+#define BOOTINFO_O_FORCE_INIT (1<<3)
+
+/*
+ * Define the API from bootinfo.h. File is not (yet ?)
+ * exported by the library, and they are defined here.
+ */
+struct bootinfo_context_s;
+typedef struct bootinfo_context_s bootinfo_context_t;
+extern int bootinfo_open(unsigned int flags, bootinfo_context_t **ctxp);
+extern int bootinfo_close(bootinfo_context_t *ctx);
+extern int bootinfo_var_get(bootinfo_context_t *ctx, const char *name, char *valuebuf, size_t valuebuf_size);
+extern int bootinfo_var_set(bootinfo_context_t *ctx, const char *name, const char *value);
+
+/*
+ * Structure for external library callbacks
+ */
+static struct {
+ int (*open)(unsigned int flags, bootinfo_context_t **ctxp);
+ int (*close)(bootinfo_context_t *ctx);
+ int (*get_env)(bootinfo_context_t *ctx, const char *name, char *valuebuf, size_t valuebuf_size);
+ int (*set_env)(bootinfo_context_t *ctx, const char *name, const char *value);
+} libcboot;
+
+static char *do_env_get(const char *name)
+{
+ bootinfo_context_t *ctx;
+ static char valuebuf[65536];
+ char *value;
+
+ if (!name)
+ return NULL;
+
+ if (libcboot.open(BOOTINFO_O_RDONLY, &ctx) < 0) {
+ ERROR("libcboot.open returns with error");
+ return NULL;
+ }
+
+ if (libcboot.get_env(ctx, name, valuebuf, sizeof(valuebuf)) < 0)
+ valuebuf[0] = '\0';
+
+ value = strdup(valuebuf);
+
+ if (libcboot.close(ctx) < 0) {
+ ERROR("libcboot.close returns with error, environmen not saved");
+ }
+ return value;
+}
+
+static int do_env_set(const char *name, const char *value)
+{
+ int ret = 0;
+ bootinfo_context_t *ctx;
+
+ if (!name || !value)
+ return -EINVAL;
+
+ if (libcboot.open(BOOTINFO_O_RDWR, &ctx) < 0) {
+ ERROR("libcboot.open returns with error");
+ return -ENOENT;
+ }
+ if (libcboot.set_env(ctx, name, value) < 0) {
+ ERROR("libcboot.set_env");
+ ret = -EFAULT;
+ }
+ if (libcboot.close(ctx) < 0) {
+ ERROR("libcboot.close returns with error, environment not saved");
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
+static int do_env_unset(const char *name)
+{
+ int ret = 0;
+ bootinfo_context_t *ctx;
+
+ if (!name)
+ return -EINVAL;
+
+ if (libcboot.open(BOOTINFO_O_RDWR, &ctx) < 0) {
+ ERROR("libcboot.open returns with error");
+ return -ENOENT;
+ }
+ if (libcboot.set_env(ctx, name, NULL) < 0) {
+ ERROR("libcboot.set_env for unset");
+ ret = -EFAULT;
+ }
+ if (libcboot.close(ctx) < 0) {
+ ERROR("libcboot.close returns with error, environment not saved");
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
+static int do_apply_list(const char *filename)
+{
+ errno = 0;
+ bootinfo_context_t *ctx;
+
+ FILE *file = fopen(filename, "rb");
+ if (!file) {
+ ERROR("Cannot open bootloader environment source file %s: %s",
+ filename, strerror(errno));
+ return -EIO;
+ }
+
+ char *line = NULL;
+ size_t length = 0;
+ int result = 0;
+ if (libcboot.open(BOOTINFO_O_RDWR, &ctx) < 0) {
+ ERROR("libcboot.open returns with error");
+ return -ENOENT;
+ }
+ while ((getline(&line, &length, file)) != -1) {
+ char *key = strtok(line, "=");
+ char *value = strtok(NULL, "\t\n");
+ if (key != NULL) {
+ result = libcboot.set_env(ctx, key, value);
+ if (result < 0) {
+ ERROR("Error %s boot var %s(%s)", value ? "storing" : "deleting",
+ key, value ? value : "");
+ }
+ }
+ }
+
+ if (libcboot.close(ctx) < 0) {
+ ERROR("libcboot.close returns with error, environment not saved");
+ result = -EFAULT;
+ }
+ fclose(file);
+ free(line);
+ return result;
+}
+
+static bootloader cboot = {
+ .env_get = &do_env_get,
+ .env_set = &do_env_set,
+ .env_unset = &do_env_unset,
+ .apply_list = &do_apply_list
+};
+
+static bootloader* probe(void)
+{
+#if defined(BOOTLOADER_STATIC_LINKED)
+ libcboot.open = bootinfo_open;
+ libcboot.close = bootinfo_close;
+ libcboot.get_env = bootinfo_var_get;
+ libcboot.set_env = bootinfo_var_set;
+#else
+ void* handle = dlopen("libtegra-boot-tools.so.1", RTLD_NOW | RTLD_GLOBAL);
+ if (!handle) {
+ return NULL;
+ }
+
+ (void)dlerror();
+ load_symbol(handle, &libcboot.open, "bootinfo_open");
+ load_symbol(handle, &libcboot.close, "bootinfo_close");
+ load_symbol(handle, &libcboot.get_env, "bootinfo_var_get");
+ load_symbol(handle, &libcboot.set_env, "bootinfo_var_set");
+#endif
+ return &cboot;
+}
+
+__attribute__((constructor))
+static void cboot_probe(void)
+{
+ (void)register_bootloader(BOOTLOADER_CBOOT, probe());
+}
@@ -12,6 +12,7 @@
#define BOOTLOADER_NONE "none"
#define BOOTLOADER_GRUB "grub"
#define BOOTLOADER_UBOOT "uboot"
+#define BOOTLOADER_CBOOT "cboot"
#define load_symbol(handle, container, fname) \
*(void**)(container) = dlsym(handle, fname); \
Some NVIDIA Tegra SOCs do not support U-Boot. NVIDIA has developed an own bootloader as replacement for U-Boot. cboot (it should be patched) can have access to the "bootinfo" database, that is stored on dependency of the SOC type on fixed memory. The tegra-boot-tools provide a convenient library to access programmatically to the environment. The environment is redundant like in U-Boot, and this gurantees to have a power-cut safe update of the variables. This patch intoduce Tegra's "bootinfo" as bootloader interface, and it depends on the libtegra-boot-tools library. Signed-off-by: Stefano Babic <sbabic@denx.de> --- Kconfig | 4 + Makefile.deps | 4 + Makefile.flags | 8 ++ bootloader/Config.in | 19 +++++ bootloader/Makefile | 1 + bootloader/cboot.c | 197 +++++++++++++++++++++++++++++++++++++++++++ include/bootloader.h | 1 + 7 files changed, 234 insertions(+) create mode 100644 bootloader/cboot.c