[PATCH] discover: add platform-uboot
Samuel Mendoza-Jonas
sam at mendozajonas.com
Tue May 14 16:05:47 AEST 2019
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 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?
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);
More information about the Petitboot
mailing list