From patchwork Mon Apr 9 02:22:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ge Song X-Patchwork-Id: 896085 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40KDdv49v5z9rvt for ; Mon, 9 Apr 2018 12:24:35 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FnCvWJ+p"; 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 40KDdv2GnfzDrqF for ; Mon, 9 Apr 2018 12:24:35 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FnCvWJ+p"; dkim-atps=neutral X-Original-To: petitboot@lists.ozlabs.org Delivered-To: petitboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:400e:c00::236; helo=mail-pf0-x236.google.com; envelope-from=songgebird@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FnCvWJ+p"; dkim-atps=neutral Received: from mail-pf0-x236.google.com (mail-pf0-x236.google.com [IPv6:2607:f8b0:400e:c00::236]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40KDdV59kSzDrpY for ; Mon, 9 Apr 2018 12:24:14 +1000 (AEST) Received: by mail-pf0-x236.google.com with SMTP id g14so4922047pfh.3 for ; Sun, 08 Apr 2018 19:24:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=Q2WXbpl6MTzEgCdRdxYXCNV7Yu6T0kGbfqAdz4uGRfo=; b=FnCvWJ+puYepC/nz3GwdCU0Vt2FaaFVTQ99isoERkb2tTmq3Wui5bXVHOkx6/QmNKD zcxyu7RxDmhnuAl1TG0WBlD7F8IGc7x3dlrmxxgCrxDY3naEF0vD9XvH0RGd7gzn/D9N Uxh0HKLjSt4//k4hk4V0DtLwJor5K05kZ6hIenWhSY8omF3N2poGBdiAtLl3No88wrSI L671myem3zD/43NHsxK9j3JnnR3UK+/lox325Hh7jJyX2PVFg2CNoWGbabQXlnr3to54 a1t/V8zFIITcg9xWQQHn2YAYxLVa5uq+mAju0F08CiFxI6wlg1zBE3wqhgbHxkAmYkIR afyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=Q2WXbpl6MTzEgCdRdxYXCNV7Yu6T0kGbfqAdz4uGRfo=; b=taIreeEvVG8Z2vOkG37hffg6qnNnXE53r6y6JwQDZdjFc/C7v1ANviSDOBy6xSqa+x 1tvFbVaXW7hXsJzeurSp41BGiawhKD1X56U0r10yDNPykgzQBmbL6sLgSSbBZvcTsZ2b 3CM96qdmWVhFnnC2p5vs8iJZgtG5FueI1MGS+yEcsgNRERn83R25pbevWMIrkEAUaf96 yvzSfTCMC+WA2y7MP+cmRWXdKADVxYvqSrFAYIwHMeV0djhCIwaYhwzdWSRjq8HT7qvQ tyfXpgyqTu9vpJvQ95LJkzWHs1H/whub9XcWsPXLYmFtWjGzLWVwscZBsfkrzokhudbE vCuA== X-Gm-Message-State: AElRT7HqdNU/9X2jPOWHVvGSDZleSnIPsT1rQwBl41A1ha3T0agc+Gea yRi6UDdZk48Urc7zYLUolhWW6Q== X-Google-Smtp-Source: AIpwx49TY1dN8PmweiTl3lOyuHAiCyOJHc7638AW289n+PzwO3lH6NCPgUlwRpx2uqLVpviHvqMWnw== X-Received: by 10.98.194.142 with SMTP id w14mr27555238pfk.226.1523240652025; Sun, 08 Apr 2018 19:24:12 -0700 (PDT) Received: from vbox.hxtcorp.net ([101.81.130.12]) by smtp.gmail.com with ESMTPSA id i127sm24587548pgc.12.2018.04.08.19.24.10 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 08 Apr 2018 19:24:11 -0700 (PDT) From: Ge Song X-Google-Original-From: Ge Song To: petitboot@lists.ozlabs.org Subject: [PATCH v2 2/2] Platform: Add support for arm64 platform. Date: Mon, 9 Apr 2018 10:22:02 +0800 Message-Id: <20180409022202.16476-3-ge.song@hxt-semitech.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180409022202.16476-1-ge.song@hxt-semitech.com> References: <20180409022202.16476-1-ge.song@hxt-semitech.com> X-BeenThere: petitboot@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Petitboot bootloader development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: petitboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Petitboot" Platform: Add a platform file which is suitable for arm64 platform. Besides, this can applies to x86/x64 platforms which adopt efi as their underlying firmware. Signed-off-by: Ge Song --- discover/Makefile.am | 3 +- discover/platform-arm64.c | 744 ++++++++++++++++++++ 2 files changed, 746 insertions(+), 1 deletion(-) diff --git a/discover/Makefile.am b/discover/Makefile.am index 4a6cbd094737..db26c14e0e46 100644 --- a/discover/Makefile.am +++ b/discover/Makefile.am @@ -81,7 +81,8 @@ discover_platform_ro_SOURCES = \ discover/dt.c \ discover/dt.h \ discover/hostboot.h \ - discover/platform-powerpc.c + discover/platform-powerpc.c \ + discover/platform-arm64.c discover_platform_ro_CPPFLAGS = \ $(AM_CPPFLAGS) diff --git a/discover/platform-arm64.c b/discover/platform-arm64.c new file mode 100644 index 000000000000..34588d8ffc1f --- /dev/null +++ b/discover/platform-arm64.c @@ -0,0 +1,744 @@ +/* + * Defines an arm64 platform, based on the powerpc platform. + * + * Actually, this is apply to platforms that adopt efi as its underlying + * firmware(x86/x64/arm64). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights + * reserved. + * Author: Ge Song + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "efi/efivar.h" +#include "ipmi.h" +#include "platform.h" +#include "talloc/talloc.h" + +#define DEF_ATTR (EFI_VARIABLE_NON_VOLATILE | \ + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS) +static const char *pb_vars_guid = "fb78ab4b-bd43-41a0-99a2-4e74bef9169b"; +static const int ipmi_timeout = 10000; /* milliseconds. */ + +struct param { + char *name; + char *value; + bool modified; + struct list_item list; +}; + +struct platform_arm64 { + struct list params; + struct ipmi *ipmi; +}; + +static const char *known_params[] = { + "auto-boot?", + "network", + "timeout", + "bootdevs", + "language", + "debug?", + "write?", + "snapshots?", + "console", + "http_proxy", + "https_proxy", + NULL, +}; + +static inline struct platform_arm64 *to_platform_arm64(struct platform *p) +{ + return (struct platform_arm64 *)(p->platform_data); +} + +static void parse_nvram(struct platform_arm64 *platform) +{ + int i, rc; + size_t size; + uint32_t attr; + uint8_t *data; + const char *pb_guid = pb_vars_guid; + char *known_param; + struct param *param; + + for (i = 0; known_params[i]; i++) { + known_param = known_params[i]; + rc = efi_get_variable(platform, pb_guid, known_param, + &data, &size, &attr); + if (!rc) { + param = talloc(platform, struct param); + param->modified = false; + param->name = talloc_strdup(platform, known_param); + param->value = talloc_strdup(platform, (char *)data); + list_add(&platform->params, ¶m->list); + } + } +} + +static void write_nvram(struct platform_arm64 *platform) +{ + struct param *param; + const char *pb_guid = pb_vars_guid; + uint32_t attr = DEF_ATTR; + size_t data_size; + + list_for_each_entry(&platform->params, param, list) { + if (param->modified) { + data_size = strlen(param->value) + 1; + efi_set_variable(platform, pb_guid, param->name, + (uint8_t *)param->value, data_size, attr); + } + } +} + +static const char *get_param(struct platform_arm64 *platform, + const char *name) +{ + struct param *param; + + list_for_each_entry(&platform->params, param, list) + if (!strcmp(param->name, name)) + return param->value; + return NULL; +} + +static void set_param(struct platform_arm64 *platform, const char *name, + const char *value) +{ + struct param *param; + + list_for_each_entry(&platform->params, param, list) { + if (strcmp(param->name, name)) + continue; + + if (!strcmp(param->value, value)) + return; + + talloc_free(param->value); + param->value = talloc_strdup(param, value); + param->modified = true; + return; + } + + param = talloc(platform, struct param); + param->modified = true; + param->name = talloc_strdup(platform, name); + param->value = talloc_strdup(platform, value); + list_add(&platform->params, ¶m->list); +} + +static int parse_hwaddr(struct interface_config *ifconf, char *str) +{ + int i; + + if (strlen(str) != strlen("00:00:00:00:00:00")) + return -1; + + for (i = 0; i < HWADDR_SIZE; i++) { + char byte[3], *endp; + unsigned long x; + + byte[0] = str[i * 3 + 0]; + byte[1] = str[i * 3 + 1]; + byte[2] = '\0'; + + x = strtoul(byte, &endp, 16); + if (endp != byte + 2) + return -1; + + ifconf->hwaddr[i] = x & 0xff; + } + + return 0; +} + +static int parse_one_interface_config(struct config *config, + char *confstr) +{ + struct interface_config *ifconf; + char *tok, *saveptr; + + ifconf = talloc_zero(config, struct interface_config); + + if (!confstr || !strlen(confstr)) + goto out_err; + + /* first token should be the mac address */ + tok = strtok_r(confstr, ",", &saveptr); + if (!tok) + goto out_err; + + if (parse_hwaddr(ifconf, tok)) + goto out_err; + + /* second token is the method */ + tok = strtok_r(NULL, ",", &saveptr); + if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) { + ifconf->ignore = true; + + } else if (!strcmp(tok, "dhcp")) { + ifconf->method = CONFIG_METHOD_DHCP; + + } else if (!strcmp(tok, "static")) { + ifconf->method = CONFIG_METHOD_STATIC; + + /* ip/mask, [optional] gateway, [optional] url */ + tok = strtok_r(NULL, ",", &saveptr); + if (!tok) + goto out_err; + ifconf->static_config.address = + talloc_strdup(ifconf, tok); + + tok = strtok_r(NULL, ",", &saveptr); + if (tok) { + ifconf->static_config.gateway = + talloc_strdup(ifconf, tok); + } + + tok = strtok_r(NULL, ",", &saveptr); + if (tok) { + ifconf->static_config.url = + talloc_strdup(ifconf, tok); + } + + } else { + pb_log("Unknown network configuration method %s\n", tok); + goto out_err; + } + + config->network.interfaces = talloc_realloc(config, + config->network.interfaces, + struct interface_config *, + ++config->network.n_interfaces); + + config->network.interfaces[config->network.n_interfaces - 1] = ifconf; + + return 0; +out_err: + talloc_free(ifconf); + return -1; +} + +static int parse_one_dns_config(struct config *config, + char *confstr) +{ + char *tok, *saveptr = NULL; + + for (tok = strtok_r(confstr, ",", &saveptr); tok; + tok = strtok_r(NULL, ",", &saveptr)) { + + char *server = talloc_strdup(config, tok); + + config->network.dns_servers = talloc_realloc(config, + config->network.dns_servers, const char *, + ++config->network.n_dns_servers); + + config->network.dns_servers[config->network.n_dns_servers - 1] + = server; + } + + return 0; +} + +static void populate_network_config(struct platform_arm64 *platform, + struct config *config) +{ + char *val, *saveptr = NULL; + const char *cval; + int i; + + cval = get_param(platform, "network"); + if (!cval || !strlen(cval)) + return; + + val = talloc_strdup(config, cval); + + for (i = 0; ; i++) { + char *tok; + + tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr); + if (!tok) + break; + + if (!strncasecmp(tok, "dns,", strlen("dns,"))) + parse_one_dns_config(config, tok + strlen("dns,")); + else + parse_one_interface_config(config, tok); + + } + + talloc_free(val); +} + +static int read_bootdev(void *ctx, char **pos, struct autoboot_option *opt) +{ + char *delim = strchr(*pos, ' '); + int len, prefix = 0, rc = -1; + enum device_type type; + + if (!strncmp(*pos, "uuid:", strlen("uuid:"))) { + prefix = strlen("uuid:"); + opt->boot_type = BOOT_DEVICE_UUID; + } else if (!strncmp(*pos, "mac:", strlen("mac:"))) { + prefix = strlen("mac:"); + opt->boot_type = BOOT_DEVICE_UUID; + } else { + type = find_device_type(*pos); + if (type != DEVICE_TYPE_UNKNOWN) { + opt->type = type; + opt->boot_type = BOOT_DEVICE_TYPE; + rc = 0; + } + } + + if (opt->boot_type == BOOT_DEVICE_UUID) { + if (delim) + len = (int)(delim - *pos) - prefix; + else + len = strlen(*pos) - prefix; + + if (len) { + opt->uuid = talloc_strndup(ctx, *pos + prefix, len); + rc = 0; + } + } + + /* Always advance pointer to next option or end */ + if (delim) + *pos = delim + 1; + else + *pos += strlen(*pos); + + return rc; +} + +static void populate_bootdev_config(struct platform_arm64 *platform, + struct config *config) +{ + struct autoboot_option *opt, *new = NULL; + char *pos, *end; + unsigned int n_new = 0; + const char *val; + + /* Check for ordered bootdevs */ + val = get_param(platform, "bootdevs"); + if (!val || !strlen(val)) { + pos = end = NULL; + } else { + pos = talloc_strdup(config, val); + end = strchr(pos, '\0'); + } + + while (pos && pos < end) { + opt = talloc(config, struct autoboot_option); + + if (read_bootdev(config, &pos, opt)) { + pb_log("bootdev config is in an unknown format " + "(expected uuid:... or mac:...)\n"); + talloc_free(opt); + continue; + } + + new = talloc_realloc(config, new, struct autoboot_option, + n_new + 1); + new[n_new] = *opt; + n_new++; + talloc_free(opt); + + } + + if (!n_new) { + /* If autoboot has been disabled, clear the default options */ + if (!config->autoboot_enabled) { + talloc_free(config->autoboot_opts); + config->n_autoboot_opts = 0; + } + return; + } + + talloc_free(config->autoboot_opts); + config->autoboot_opts = new; + config->n_autoboot_opts = n_new; +} + +static void populate_config(struct platform_arm64 *platform, + struct config *config) +{ + const char *val; + char *end; + unsigned long timeout; + + /* if the "auto-boot?' property is present and "false", disable auto + * boot */ + val = get_param(platform, "auto-boot?"); + config->autoboot_enabled = !val || strcmp(val, "false"); + + val = get_param(platform, "timeout"); + if (val) { + timeout = strtoul(val, &end, 10); + if (end != val) { + if (timeout >= INT_MAX) + timeout = INT_MAX; + config->autoboot_timeout_sec = (int)timeout; + } + } + + val = get_param(platform, "language"); + config->lang = val ? talloc_strdup(config, val) : NULL; + + populate_network_config(platform, config); + + populate_bootdev_config(platform, config); + + if (!config->debug) { + val = get_param(platform, "debug?"); + config->debug = val && !strcmp(val, "true"); + } + + val = get_param(platform, "write?"); + if (val) + config->allow_writes = !strcmp(val, "true"); + + val = get_param(platform, "snapshots?"); + if (val) + config->disable_snapshots = !strcmp(val, "false"); + + val = get_param(platform, "console"); + if (val) + config->boot_console = talloc_strdup(config, val); + /* If a full path is already set we don't want to override it */ + config->manual_console = config->boot_console && + !strchr(config->boot_console, '['); + + val = get_param(platform, "http_proxy"); + if (val) + config->http_proxy = talloc_strdup(config, val); + val = get_param(platform, "https_proxy"); + if (val) + config->https_proxy = talloc_strdup(config, val); +} + +static char *iface_config_str(void *ctx, struct interface_config *config) +{ + char *str; + + /* todo: HWADDR size is hardcoded as 6, but we may need to handle + * different hardware address formats */ + str = talloc_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x,", + config->hwaddr[0], config->hwaddr[1], + config->hwaddr[2], config->hwaddr[3], + config->hwaddr[4], config->hwaddr[5]); + + if (config->ignore) { + str = talloc_asprintf_append(str, "ignore"); + + } else if (config->method == CONFIG_METHOD_DHCP) { + str = talloc_asprintf_append(str, "dhcp"); + + } else if (config->method == CONFIG_METHOD_STATIC) { + str = talloc_asprintf_append(str, "static,%s%s%s%s%s", + config->static_config.address, + config->static_config.gateway ? "," : "", + config->static_config.gateway ?: "", + config->static_config.url ? "," : "", + config->static_config.url ?: ""); + } + return str; +} + +static char *dns_config_str(void *ctx, const char **dns_servers, int n) +{ + char *str; + int i; + + str = talloc_strdup(ctx, "dns,"); + for (i = 0; i < n; i++) { + str = talloc_asprintf_append(str, "%s%s", + i == 0 ? "" : ",", + dns_servers[i]); + } + + return str; +} + +static void update_string_config(struct platform_arm64 *platform, + const char *name, const char *value) +{ + const char *cur; + + cur = get_param(platform, name); + + /* don't set an empty parameter if it doesn't already exist */ + if (!cur && !strlen(value)) + return; + + set_param(platform, name, value); +} + +static void update_network_config(struct platform_arm64 *platform, + struct config *config) +{ + unsigned int i; + char *val; + + /* + * Don't store IPMI overrides to NVRAM. If this was a persistent + * override it was already stored in NVRAM by + * get_ipmi_network_override() + */ + if (config->network.n_interfaces && + config->network.interfaces[0]->override) + return; + + val = talloc_strdup(platform, ""); + + for (i = 0; i < config->network.n_interfaces; i++) { + char *iface_str = iface_config_str(platform, + config->network.interfaces[i]); + val = talloc_asprintf_append(val, "%s%s", + *val == '\0' ? "" : " ", iface_str); + talloc_free(iface_str); + } + + if (config->network.n_dns_servers) { + char *dns_str = dns_config_str(platform, + config->network.dns_servers, + config->network.n_dns_servers); + val = talloc_asprintf_append(val, "%s%s", + *val == '\0' ? "" : " ", dns_str); + talloc_free(dns_str); + } + + update_string_config(platform, "network", val); + + talloc_free(val); +} + +static void update_bootdev_config(struct platform_arm64 *platform, + struct config *config) +{ + char *val = NULL, *boot_str = NULL, *tmp = NULL; + struct autoboot_option *opt; + const char delim = ' '; + unsigned int i; + + if (!config->n_autoboot_opts) + val = ""; + + for (i = 0; i < config->n_autoboot_opts; i++) { + opt = &config->autoboot_opts[i]; + switch (opt->boot_type) { + case BOOT_DEVICE_TYPE: + boot_str = talloc_asprintf(config, "%s%c", + device_type_name(opt->type), + delim); + break; + case BOOT_DEVICE_UUID: + boot_str = talloc_asprintf(config, "uuid:%s%c", + opt->uuid, delim); + break; + } + tmp = val = talloc_asprintf_append(val, "%s", boot_str); + } + + update_string_config(platform, "bootdevs", val); + talloc_free(tmp); + if (boot_str) + talloc_free(boot_str); +} + +static void update_config(struct platform_arm64 *platform, + struct config *config, struct config *defaults) +{ + char *tmp = NULL; + const char *val; + + if (config->autoboot_enabled == defaults->autoboot_enabled) + val = ""; + else + val = config->autoboot_enabled ? "true" : "false"; + update_string_config(platform, "auto-boot?", val); + + if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec) + val = ""; + else + val = tmp = talloc_asprintf(platform, "%d", + config->autoboot_timeout_sec); + + update_string_config(platform, "timeout", val); + if (tmp) + talloc_free(tmp); + + val = config->lang ?: ""; + update_string_config(platform, "language", val); + + if (config->allow_writes == defaults->allow_writes) + val = ""; + else + val = config->allow_writes ? "true" : "false"; + update_string_config(platform, "write?", val); + + if (!config->manual_console) { + val = config->boot_console ?: ""; + update_string_config(platform, "console", val); + } + + val = config->http_proxy ?: ""; + update_string_config(platform, "http_proxy", val); + val = config->https_proxy ?: ""; + update_string_config(platform, "https_proxy", val); + + update_network_config(platform, config); + + update_bootdev_config(platform, config); + + write_nvram(platform); +} + +static void get_ipmi_bmc_mac(struct platform *p, uint8_t *buf) +{ + struct platform_arm64 *platform = p->platform_data; + uint16_t resp_len = 8; + uint8_t resp[8]; + uint8_t req[] = { 0x1, 0x5, 0x0, 0x0 }; + int i, rc; + + rc = ipmi_transaction(platform->ipmi, IPMI_NETFN_TRANSPORT, + IPMI_CMD_TRANSPORT_GET_LAN_PARAMS, + req, sizeof(req), + resp, &resp_len, + ipmi_timeout); + + pb_debug("BMC MAC resp [%d][%d]:\n", rc, resp_len); + + if (rc == 0 && resp_len > 0) { + for (i = 2; i < resp_len; i++) { + pb_debug(" %x", resp[i]); + buf[i - 2] = resp[i]; + } + pb_debug("\n"); + } + +} + +static void get_active_consoles(struct config *config) +{ + config->n_consoles = 3; + config->consoles = talloc_array(config, char *, config->n_consoles); + if (!config->consoles) + goto err; + + config->consoles[0] = talloc_asprintf(config->consoles, + "/dev/hvc0 [IPMI / Serial]"); + config->consoles[1] = talloc_asprintf(config->consoles, + "/dev/ttyAMA0 [Serial]"); + config->consoles[2] = 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_arm64 *platform = to_platform_arm64(p); + + parse_nvram(platform); + + populate_config(platform, config); + + get_active_consoles(config); + + return 0; +} + +static int save_config(struct platform *p, struct config *config) +{ + struct platform_arm64 *platform = to_platform_arm64(p); + struct config *defaults; + + defaults = talloc_zero(platform, struct config); + config_set_defaults(defaults); + + update_config(platform, config, defaults); + + talloc_free(defaults); + + return 0; +} + +static int get_sysinfo(struct platform *p, struct system_info *sysinfo) +{ + struct platform_arm64 *platform = p->platform_data; + + sysinfo->bmc_mac = talloc_zero_size(sysinfo, HWADDR_SIZE); + + if (platform->ipmi) + get_ipmi_bmc_mac(p, sysinfo->bmc_mac); + + return 0; +} + +static bool probe(struct platform *p, void *ctx) +{ + struct platform_arm64 *platform; + const char *path = "/sys/firmware/efi/efivars/"; + int rc = 0; + struct statfs buf; + + if (access(path, F_OK)) + return false; + + memset(&buf, '\0', sizeof(buf)); + rc = statfs(path, &buf); + if (rc) + return false; + + typeof(buf.f_type) magic = EFIVARFS_MAGIC; + if (!memcmp(&buf.f_type, &magic, sizeof (magic))) { + platform = talloc_zero(ctx, struct platform_arm64); + list_init(&platform->params); + p->platform_data = platform; + return true; + } + + return false; +} + +static struct platform platform_arm64 = { + .name = "arm64", + .dhcp_arch_id = 0x000d, + .probe = probe, + .load_config = load_config, + .save_config = save_config, + .get_sysinfo = get_sysinfo, +}; + +register_platform(platform_arm64);