[PATCH] discover: add platform-uboot
Marty E. Plummer
hanetzer at startmail.com
Thu May 2 12:12:12 AEST 2019
Currently exists as a fairly cut-down version of platform-powerpc.c
Signed-off-by: Marty E. Plummer <hanetzer at startmail.com>
---
Greets all. As mentioned in the commit message, this is pretty much a
clone of platform-powerpc.c, it more or less works, but I've found an
issue I'm not sure how to get around based on the existing code.
At some point, the equivalent of `fw_setenv autoboot? true` gets called,
but this ? corrupts the env. I'd have to do (manually from userspace)
the following to get it saved right: `fw_setenv autoboot\? true`, but
I'm not sure how, if at all, I can escape this in talloc_asprintf.
Does anyone have any suggestions as to how to do this?
Marty E. Plummer
---
Note: I currently have platform-uboot.c above platform-arm64.c because
the probe function of arm64 does match what I have and will be
prioritized over platform-uboot.c, this relates to my previous mailing
about code sharing among arch's and firmware platforms (eg, mixing
platform-efi.c [currently no-existant] and platfom-x86_64.c [same])
configure.ac | 18 ++-
discover/Makefile.am | 4 +
discover/platform-uboot.c | 274 ++++++++++++++++++++++++++++++++++++++
3 files changed, 294 insertions(+), 2 deletions(-)
create mode 100644 discover/platform-uboot.c
diff --git a/configure.ac b/configure.ac
index 5d541fb..c66aabc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -334,7 +334,12 @@ AC_ARG_ENABLE(
)
AS_IF(
[test "x$enable_platform_all" = "xyes"],
- [enable_platform_arm64="yes"; enable_platform_powerpc="yes"; enable_platform_ps3="yes"]
+ [
+ enable_platform_arm64="yes";
+ enable_platform_powerpc="yes";
+ enable_platform_ps3="yes";
+ enable_platform_uboot="yes"
+ ]
)
AC_ARG_ENABLE(
@@ -349,7 +354,7 @@ AC_ARG_ENABLE(
AS_IF(
[test "x$enable_platform_auto" = "xyes"],
[AS_CASE([$host],
- [aarch64-*-*], [enable_platform_arm64="yes"],
+ [aarch64-*-*], [enable_platform_arm64="yes";enable_platform_uboot="yes"],
[powerpc*-*-*], [enable_platform_powerpc="yes"],
)]
)
@@ -380,6 +385,15 @@ AC_ARG_ENABLE(
)])
AM_CONDITIONAL([PLATFORM_PS3], [test "x$enable_platform_ps3" = "xyes"])
+AC_ARG_ENABLE(
+ [platform-uboot],
+ [AS_HELP_STRING(
+ [--enable-platform-uboot],
+ [build support for uboot platforms [default=no]]
+ )]
+)
+AM_CONDITIONAL([PLATFORM_UBOOT], [test "x$enable_platform_uboot" = "xyes"])
+
AC_ARG_ENABLE(
[debug],
[AS_HELP_STRING([--enable-debug],
diff --git a/discover/Makefile.am b/discover/Makefile.am
index bfe33fa..b95a7e3 100644
--- a/discover/Makefile.am
+++ b/discover/Makefile.am
@@ -81,6 +81,10 @@ discover_platform_ro_SOURCES = \
discover/dt.h \
discover/hostboot.h
+if PLATFORM_UBOOT
+discover_platform_ro_SOURCES += discover/platform-uboot.c
+endif
+
if PLATFORM_ARM64
discover_platform_ro_SOURCES += discover/platform-arm64.c
endif
diff --git a/discover/platform-uboot.c b/discover/platform-uboot.c
new file mode 100644
index 0000000..1705a46
--- /dev/null
+++ b/discover/platform-uboot.c
@@ -0,0 +1,274 @@
+#include <string.h>
+#include <sys/stat.h>
+
+#include <file/file.h>
+#include <log/log.h>
+#include <process/process.h>
+#include <talloc/talloc.h>
+#include <crypt/crypt.h>
+
+#include "platform.h"
+
+static const char *devtree_dir = "/proc/device-tree";
+
+struct platform_uboot {
+ struct param_list *params;
+};
+
+#define to_platform_uboot(p) \
+ (struct platform_uboot*)(p->platform_data)
+
+static int parse_nvram_params(struct platform_uboot *platform,
+ char *buf, int len)
+{
+ char *pos, *name, *value;
+ unsigned int paramlen;
+
+ for (pos = buf; pos < buf + len; pos += paramlen + 1) {
+ unsigned int namelen;
+ char *newline;
+
+ newline = strchr(pos, '\n');
+ if (!newline)
+ break;
+
+ *newline = '\0';
+
+ paramlen = strlen(pos);
+
+ name = pos;
+ value = strchr(pos, '=');
+ if (!value)
+ continue;
+
+ namelen = value - name;
+ if (namelen == 0)
+ continue;
+
+ if (!param_list_is_known_n(platform->params, name, namelen))
+ continue;
+
+ *value = '\0';
+ value++;
+
+ param_list_set(platform->params, name, value, false);
+ }
+
+ return 0;
+}
+
+static int parse_nvram(struct platform_uboot *platform)
+{
+ struct process_stdout *stdout;
+ const char *argv[2];
+ int rc;
+
+ argv[0] = "fw_printenv";
+ argv[1] = NULL;
+
+ rc = process_get_stdout_argv(NULL, &stdout, argv);
+
+ if (rc) {
+ fprintf(stderr, "fw_printenv process returned "
+ "non-zero exit status\n");
+ rc = -1;
+ } else {
+ rc = parse_nvram_params(platform, stdout->buf, stdout->len);
+ }
+
+ talloc_free(stdout);
+ return rc;
+}
+
+static int write_nvram(struct platform_uboot *platform)
+{
+ struct process *process;
+ struct param *param;
+ const char *argv[4];
+ int rc = 0;
+
+ argv[0] = "fw_setenv";
+ argv[1] = NULL;
+ argv[2] = NULL;
+ argv[3] = NULL;
+
+ process = process_create(platform);
+ process->path = "fw_setenv";
+ process->argv = argv;
+
+ param_list_for_each(platform->params, param) {
+ char *paramname, *paramval;
+
+ if (!param->modified)
+ continue;
+
+ paramname = talloc_asprintf(platform, "%s", param->name);
+ argv[1] = paramname;
+
+ paramval = talloc_asprintf(platform, "%s", param->value);
+ argv[2] = paramval;
+
+ rc = process_run_sync(process);
+
+ talloc_free(paramname);
+ talloc_free(paramval);
+
+ if (rc || !process_exit_ok(process)) {
+ rc = -1;
+ pb_log("fw_setenv process returned non-zero exit status\n");
+ break;
+ }
+ }
+
+ process_release(process);
+ return rc;
+}
+
+static void params_update_all(struct param_list *pl, const struct config *config,
+ const struct config *defaults)
+{
+ char *tmp = NULL;
+ const char *val;
+
+ if (config->autoboot_enabled == defaults->autoboot_enabled)
+ val = "";
+ else
+ val = config->autoboot_enabled ? "true" : "false";
+
+ param_list_set_non_empty(pl, "auto-boot?", val, true);
+
+ if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
+ val = "";
+ else
+ val = tmp = talloc_asprintf(pl, "%d", config->autoboot_timeout_sec);
+
+ param_list_set_non_empty(pl, "petitboot,timeout", val, true);
+ if (tmp)
+ talloc_free(tmp);
+
+ val = config->lang ?: "";
+ param_list_set_non_empty(pl, "petitboot,language", val, true);
+
+ if (config->allow_writes == defaults->allow_writes)
+ val = "";
+ else
+ val = config->allow_writes ? "true" : "false";
+ param_list_set_non_empty(pl, "petitboot,write?", val, true);
+
+ if (!config->manual_console) {
+ val = config->boot_console ?: "";
+ param_list_set_non_empty(pl, "petitboot,console", val, true);
+ }
+
+ val = config->http_proxy ?: "";
+ param_list_set_non_empty(pl, "petitboot,http_proxy", val, true);
+ val = config->https_proxy ?: "";
+ param_list_set_non_empty(pl, "petitboot,https_proxy", val, true);
+
+ params_update_network_values(pl, "petitboot,network", config);
+ params_update_bootdev_values(pl, "petitboot,bootdevs", config);
+}
+
+static void config_get_active_consoles(struct config *config)
+{
+ config->n_consoles = 2;
+ config->consoles = talloc_array(config, char *, config->n_consoles);
+ if (!config->consoles)
+ goto err;
+
+ config->consoles[0] = talloc_asprintf(config->consoles,
+ "/dev/ttyS2 [Serial]");
+ config->consoles[1] = talloc_asprintf(config->consoles,
+ "/dev/tty1 [VGA]");
+
+ return;
+err:
+ config->n_consoles = 0;
+ pb_log("Failed to allocate memory for consoles\n");
+}
+
+static int load_config(struct platform *p, struct config *config)
+{
+ struct platform_uboot *platform = to_platform_uboot(p);
+ const char *hash;
+ int rc;
+
+ rc = parse_nvram(platform);
+ if (rc)
+ pb_log_fn("Failed to parse nvram\n");
+
+ config_populate_all(config, platform->params);
+
+ config_get_active_consoles(config);
+
+ hash = param_list_get_value(platform->params, "petitboot,password");
+ if (hash) {
+ rc = crypt_set_password_hash(platform, hash);
+ if (rc)
+ pb_log("Failed to set password hash\n");
+ }
+
+ return 0;
+}
+
+static int save_config(struct platform *p, struct config *config)
+{
+ struct platform_uboot *platform = to_platform_uboot(p);
+ struct config *defaults;
+
+ defaults = talloc_zero(platform, struct config);
+ config_set_defaults(defaults);
+
+ params_update_all(platform->params, config, defaults);
+
+ talloc_free(defaults);
+ return write_nvram(platform);
+}
+
+static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
+{
+ struct platform_uboot *platform = p->platform_data;
+ char *buf, *filename;
+ int len, rc;
+
+ filename = talloc_asprintf(platform, "%smodel", devtree_dir);
+ rc = read_file(platform, filename, &buf, &len);
+ if (rc == 0)
+ sysinfo->type = talloc_steal(sysinfo, buf);
+ talloc_free(filename);
+
+ return 0;
+}
+
+static bool probe(struct platform *p, void *ctx)
+{
+ struct platform_uboot *platform;
+ struct stat statbuf;
+ int rc;
+
+ rc = stat("/proc/device-tree", &statbuf);
+ if (rc)
+ return false;
+
+ if (!S_ISDIR(statbuf.st_mode))
+ return false;
+
+ platform = talloc_zero(ctx, struct platform_uboot);
+ platform->params = talloc_zero(platform, struct param_list);
+ param_list_init(platform->params, common_known_params());
+
+ p->platform_data = platform;
+
+ return true;
+}
+
+static struct platform platform_uboot = {
+ .name = "uboot",
+ .dhcp_arch_id = 0x000d,
+ .probe = probe,
+ .load_config = load_config,
+ .save_config = save_config,
+ .get_sysinfo = get_sysinfo,
+};
+
+register_platform(platform_uboot);
--
2.21.0
More information about the Petitboot
mailing list