discover: add platform-uboot
diff mbox series

Message ID 20190502021212.15802-1-hanetzer@startmail.com
State New
Headers show
Series
  • discover: add platform-uboot
Related show

Commit Message

Marty E. Plummer May 2, 2019, 2:12 a.m. UTC
Currently exists as a fairly cut-down version of platform-powerpc.c

Signed-off-by: Marty E. Plummer <hanetzer@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

Comments

Samuel Mendoza-Jonas May 14, 2019, 6:05 a.m. UTC | #1
On Wed, 2019-05-01 at 21:12 -0500, Marty E. Plummer wrote:
> Currently exists as a fairly cut-down version of platform-powerpc.c
> 
> Signed-off-by: Marty E. Plummer <hanetzer@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?

Hi Marty,

I think I saw on IRC that you found a solution to this, was there any
news?

Cheers,
Sam

> 
> 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);
Marty E. Plummer May 15, 2019, 6:44 p.m. UTC | #2
On Tue, May 14, 2019 at 04:05:47PM +1000, Samuel Mendoza-Jonas wrote:
> On Wed, 2019-05-01 at 21:12 -0500, Marty E. Plummer wrote:
> > Currently exists as a fairly cut-down version of platform-powerpc.c
> > 
> > Signed-off-by: Marty E. Plummer <hanetzer@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?
> 
> Hi Marty,
> 
> I think I saw on IRC that you found a solution to this, was there any
> news?
> 
Yeah, I think the issue arose not due to improper escaping but the fact
I made the u-boot env image wrong. Once I figured that bit out
everything started to work just fine. Still need to figure out some the
lack of genericism in the other two platforms but other than that it
should be in a workable state.

> Cheers,
> Sam
> 
> > 
> > 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);
> 
>

Patch
diff mbox series

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);