From patchwork Thu May 2 02:12:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Marty E. Plummer" X-Patchwork-Id: 1093980 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 44vf1866S8z9s9T for ; Thu, 2 May 2019 12:12:44 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=startmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=startmail.com header.i=@startmail.com header.b="QJTp59Q/"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 44vf184QPmzDqP1 for ; Thu, 2 May 2019 12:12:44 +1000 (AEST) X-Original-To: petitboot@lists.ozlabs.org Delivered-To: petitboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=startmail.com (client-ip=145.131.90.139; helo=mx-out1.startmail.com; envelope-from=hanetzer@startmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=startmail.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=startmail.com header.i=@startmail.com header.b="QJTp59Q/"; dkim-atps=neutral Received: from mx-out1.startmail.com (mx-out1.startmail.com [145.131.90.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 44vf0y41X5zDqCt for ; Thu, 2 May 2019 12:12:33 +1000 (AEST) From: "Marty E. Plummer" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=startmail.com; s=2017-11; t=1556763149; bh=R7Oun9iSZzPb1bPt5VtCTsAG7oQDbg9cq+fhYalT4CQ=; h=From:To:Cc:Subject:Date:From; b=QJTp59Q/xZSxpL7IKaOkg2UKhSN6Xe++kGtEaiu7sfb5LhEwgefwjdPZpWQ7SOEeR k4do+zNDDuWvtngmlbb3/TGpMwOR4o1KfEBggWE225g8jx0ZIEoJKgv0RWa+EGWzhG EGxA9g3fWtW7OV0CEMYGpp0T1Xa8iNfFIBJRJ9FAaYHW3kdbANMxOeQ+4c6NMgnLnr fNcLhzcPC8/M9pO1L27Ff9+6+IRDnZBugnBXqCwTJ8WisSoI/U22nZD9rPeTyGqn+H Ies0BzGAer8iZ8v1eZUO0RRb/zQuPIwKUBwaLgcuOWadt6PkUdJgCvaDy3Sk4GMTOS dLVcx4HuxwWNA== To: petitboot@lists.ozlabs.org Subject: [PATCH] discover: add platform-uboot Date: Wed, 1 May 2019 21:12:12 -0500 Message-Id: <20190502021212.15802-1-hanetzer@startmail.com> Mime-Version: 1.0 X-BeenThere: petitboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Petitboot bootloader development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "Marty E. Plummer" Errors-To: petitboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Petitboot" Currently exists as a fairly cut-down version of platform-powerpc.c Signed-off-by: Marty E. Plummer --- 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 +#include + +#include +#include +#include +#include +#include + +#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);