[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