diff --git a/discover/Makefile.am b/discover/Makefile.am
index ef4c6027d128..3681caac586b 100644
--- a/discover/Makefile.am
+++ b/discover/Makefile.am
@@ -82,7 +82,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/test/parser/Makefile.am b/test/parser/Makefile.am
index 6ff3972d8316..68eb18f7c046 100644
--- a/test/parser/Makefile.am
+++ b/test/parser/Makefile.am
@@ -123,6 +123,7 @@ test_parser_libtest_ro_SOURCES = \
 	discover/pxe-parser.c \
 	discover/syslinux-parser.c \
 	discover/platform.c \
+	discover/ipmi.c \
 	discover/resource.c \
 	discover/paths.c \
 	discover/device-handler.c \
diff --git a/discover/platform.h b/discover/platform.h
index 5aa8e3f9dcc8..919894fb0157 100644
--- a/discover/platform.h
+++ b/discover/platform.h
@@ -2,22 +2,35 @@
 #define PLATFORM_H
 
 #include <types/types.h>
+#include "ipmi.h"
 
 struct platform {
 	const char	*name;
 	bool		(*probe)(struct platform *, void *);
 	int		(*load_config)(struct platform *, struct config *);
-	int		(*save_config)(struct platform *, struct config *);
+	int		(*save_config)(struct platform *);
+	void		(*update_config)(struct platform *, struct config*);
 	void		(*pre_boot)(struct platform *,
 				const struct config *);
 	int		(*get_sysinfo)(struct platform *, struct system_info *);
+	struct list     *(*get_params_list)(struct platform *);
 	uint16_t	dhcp_arch_id;
 	void		*platform_data;
 };
 
+struct params {
+	char *name;
+	char *value;
+	bool modified;
+	struct list_item list;
+};
+
+extern const char *known_params[];
+
 int platform_init(void *ctx);
 int platform_fini(void);
 const struct platform *platform_get(void);
+void get_ipmi_bmc_mac(struct ipmi *ipmi, uint8_t *buf, int timeout);
 int platform_get_sysinfo(struct system_info *info);
 void platform_pre_boot(void);
 
@@ -25,6 +38,9 @@ void platform_pre_boot(void);
 const struct config *config_get(void);
 int config_set(struct config *config);
 void config_set_autoboot(bool autoboot_enabled);
+void populate_config(struct list *platform_params, struct config *config);
+int update_config(struct platform *p, struct config *config, struct config *defaults);
+void update_network_config(struct list *platform_params, struct config *config);
 
 /* for use by the platform-specific storage code */
 void config_set_defaults(struct config *config);
diff --git a/discover/platform-arm64.c b/discover/platform-arm64.c
new file mode 100644
index 000000000000..a427eaa8278f
--- /dev/null
+++ b/discover/platform-arm64.c
@@ -0,0 +1,195 @@
+/*
+ *  Defines an arm64 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 <ge.song@hxt-semitech.com>
+ */
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+
+#include "efi/efivar.h"
+#include "file/file.h"
+#include "list/list.h"
+#include "log/log.h"
+#include "talloc/talloc.h"
+#include "types/types.h"
+
+#include "ipmi.h"
+#include "platform.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 platform_arm64 {
+	struct list params;
+	struct ipmi *ipmi;
+};
+
+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;
+	const char *known_param;
+	struct params *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 params);
+			param->modified = false;
+			param->name = talloc_strdup(platform, known_param);
+			param->value = talloc_strdup(platform, (char *)data);
+			list_add(&platform->params, &param->list);
+		}
+	}
+}
+
+static int write_nvram(struct platform_arm64 *platform)
+{
+	struct params *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);
+		}
+	}
+
+	return 0;
+}
+
+static struct list* get_params_list(struct platform* p)
+{
+	struct platform_arm64 *platform = to_platform_arm64(p);
+
+	return &platform->params;
+}
+
+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->params, config);
+
+	get_active_consoles(config);
+
+	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(platform->ipmi, sysinfo->bmc_mac, ipmi_timeout);
+
+	return 0;
+}
+
+static int save_config(struct platform *p)
+{
+	struct platform_arm64 *platform = p->platform_data;
+
+	return write_nvram(platform);
+}
+
+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;
+		p->get_params_list = get_params_list;
+
+		set_efivarfs_path(path);
+		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);
diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
index df8c7d611d26..973cb23d5b8f 100644
--- a/discover/platform-powerpc.c
+++ b/discover/platform-powerpc.c
@@ -1,40 +1,33 @@
 
+#include <asm/byteorder.h>
 #include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <limits.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <sys/stat.h>
-#include <asm/byteorder.h>
 
 #include <file/file.h>
-#include <talloc/talloc.h>
 #include <list/list.h>
 #include <log/log.h>
 #include <process/process.h>
+#include <talloc/talloc.h>
 #include <types/types.h>
 #include <url/url.h>
 
+#include "dt.h"
 #include "hostboot.h"
-#include "platform.h"
 #include "ipmi.h"
-#include "dt.h"
+#include "platform.h"
 
 static const char *partition = "common";
 static const char *sysparams_dir = "/sys/firmware/opal/sysparams/";
 static const char *devtree_dir = "/proc/device-tree/";
 static const int ipmi_timeout = 10000; /* milliseconds. */
 
-struct param {
-	char			*name;
-	char			*value;
-	bool			modified;
-	struct list_item	list;
-};
-
 struct platform_powerpc {
 	struct list	params;
 	struct ipmi	*ipmi;
@@ -45,26 +38,11 @@ struct platform_powerpc {
 	int		(*clear_ipmi_bootdev)(
 				struct platform_powerpc *platform,
 				bool persistent);
-	int 		(*set_os_boot_sensor)(
+	int		(*set_os_boot_sensor)(
 				struct platform_powerpc *platform);
 	void		(*get_platform_versions)(struct system_info *info);
 };
 
-static const char *known_params[] = {
-	"auto-boot?",
-	"petitboot,network",
-	"petitboot,timeout",
-	"petitboot,bootdevs",
-	"petitboot,language",
-	"petitboot,debug?",
-	"petitboot,write?",
-	"petitboot,snapshots?",
-	"petitboot,console",
-	"petitboot,http_proxy",
-	"petitboot,https_proxy",
-	NULL,
-};
-
 #define to_platform_powerpc(p) \
 	(struct platform_powerpc *)(p->platform_data)
 
@@ -111,7 +89,7 @@ static int parse_nvram_params(struct platform_powerpc *platform,
 
 	for (pos = buf + i; pos < buf + len; pos += paramlen + 1) {
 		unsigned int namelen;
-		struct param *param;
+		struct params *param;
 		char *newline;
 
 		newline = strchr(pos, '\n');
@@ -136,7 +114,7 @@ static int parse_nvram_params(struct platform_powerpc *platform,
 
 		value++;
 
-		param = talloc(platform, struct param);
+		param = talloc(platform, struct params);
 		param->modified = false;
 		param->name = talloc_strndup(platform, name, namelen);
 		param->value = talloc_strdup(platform, value);
@@ -181,7 +159,7 @@ static int parse_nvram(struct platform_powerpc *platform)
 static int write_nvram(struct platform_powerpc *platform)
 {
 	struct process *process;
-	struct param *param;
+	struct params *param;
 	const char *argv[6];
 	int rc = 0;
 
@@ -222,525 +200,11 @@ static int write_nvram(struct platform_powerpc *platform)
 	return rc;
 }
 
-static const char *get_param(struct platform_powerpc *platform,
-		const char *name)
+static struct list* get_params_list(struct platform* p)
 {
-	struct param *param;
+	struct platform_powerpc *platform = to_platform_powerpc(p);
 
-	list_for_each_entry(&platform->params, param, list)
-		if (!strcmp(param->name, name))
-			return param->value;
-	return NULL;
-}
-
-static void set_param(struct platform_powerpc *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, &param->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, *tok_gw, *tok_url, *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);
-
-		/*
-		 * If a url is set but not a gateway, we can accidentally
-		 * interpret the url as the gateway. To avoid changing the
-		 * parameter format check if the "gateway" is actually a
-		 * pb-url if it's the last token.
-		 */
-		tok_gw = strtok_r(NULL, ",", &saveptr);
-		tok_url = strtok_r(NULL, ",", &saveptr);
-
-		if (tok_gw) {
-			if (tok_url || !is_url(tok_gw))
-				ifconf->static_config.gateway =
-					talloc_strdup(ifconf, tok_gw);
-			else
-					tok_url = tok_gw;
-		}
-
-		if (tok_url)
-			ifconf->static_config.url =
-				talloc_strdup(ifconf, tok_url);
-	} 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_powerpc *platform,
-		struct config *config)
-{
-	char *val, *saveptr = NULL;
-	const char *cval;
-	int i;
-
-	cval = get_param(platform, "petitboot,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_powerpc *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, "petitboot,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_powerpc *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, "petitboot,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, "petitboot,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, "petitboot,debug?");
-		config->debug = val && !strcmp(val, "true");
-	}
-
-	val = get_param(platform, "petitboot,write?");
-	if (val)
-		config->allow_writes = !strcmp(val, "true");
-
-	val = get_param(platform, "petitboot,snapshots?");
-	if (val)
-		config->disable_snapshots = !strcmp(val, "false");
-
-	val = get_param(platform, "petitboot,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, "petitboot,http_proxy");
-	if (val)
-		config->http_proxy = talloc_strdup(config, val);
-	val = get_param(platform, "petitboot,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_powerpc *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_powerpc *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, "petitboot,network", val);
-
-	talloc_free(val);
-}
-
-static void update_bootdev_config(struct platform_powerpc *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, "petitboot,bootdevs", val);
-	talloc_free(tmp);
-	if (boot_str)
-		talloc_free(boot_str);
-}
-
-static int update_config(struct platform_powerpc *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);
-
-	if (config->ipmi_bootdev == IPMI_BOOTDEV_INVALID &&
-	    platform->clear_ipmi_bootdev) {
-		platform->clear_ipmi_bootdev(platform,
-				config->ipmi_bootdev_persistent);
-		config->ipmi_bootdev = IPMI_BOOTDEV_NONE;
-		config->ipmi_bootdev_persistent = false;
-	}
-
-	update_string_config(platform, "petitboot,timeout", val);
-	if (tmp)
-		talloc_free(tmp);
-
-	val = config->lang ?: "";
-	update_string_config(platform, "petitboot,language", val);
-
-	if (config->allow_writes == defaults->allow_writes)
-		val = "";
-	else
-		val = config->allow_writes ? "true" : "false";
-	update_string_config(platform, "petitboot,write?", val);
-
-	if (!config->manual_console) {
-		val = config->boot_console ?: "";
-		update_string_config(platform, "petitboot,console", val);
-	}
-
-	val = config->http_proxy ?: "";
-	update_string_config(platform, "petitboot,http_proxy", val);
-	val = config->https_proxy ?: "";
-	update_string_config(platform, "petitboot,https_proxy", val);
-
-	update_network_config(platform, config);
-
-	update_bootdev_config(platform, config);
-
-	return write_nvram(platform);
+	return &platform->params;
 }
 
 static void set_ipmi_bootdev(struct config *config, enum ipmi_bootdev bootdev,
@@ -992,32 +456,6 @@ static int set_ipmi_os_boot_sensor(struct platform_powerpc *platform)
 	return 0;
 }
 
-static void get_ipmi_bmc_mac(struct platform *p, uint8_t *buf)
-{
-	struct platform_powerpc *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");
-	}
-
-}
-
 /*
  * Retrieve info from the "Get Device ID" IPMI commands.
  * See Chapter 20.1 in the IPMIv2 specification.
@@ -1212,7 +650,7 @@ static void get_ipmi_network_override(struct platform_powerpc *platform,
 
 	if (!rc && persistent) {
 		/* Write this new config to NVRAM */
-		update_network_config(platform, config);
+		update_network_config(&platform->params, config);
 		rc = write_nvram(platform);
 		if (rc)
 			pb_log("platform: Failed to save persistent interface override\n");
@@ -1261,7 +699,7 @@ static int load_config(struct platform *p, struct config *config)
 	if (rc)
 		pb_log("%s: Failed to parse nvram\n", __func__);
 
-	populate_config(platform, config);
+	populate_config(&platform->params, config);
 
 	if (platform->get_ipmi_bootdev) {
 		bool bootdev_persistent;
@@ -1281,19 +719,11 @@ static int load_config(struct platform *p, struct config *config)
 	return 0;
 }
 
-static int save_config(struct platform *p, struct config *config)
+static int save_config(struct platform *p)
 {
 	struct platform_powerpc *platform = to_platform_powerpc(p);
-	struct config *defaults;
-	int rc;
 
-	defaults = talloc_zero(platform, struct config);
-	config_set_defaults(defaults);
-
-	rc = update_config(platform, config, defaults);
-
-	talloc_free(defaults);
-	return rc;
+	return write_nvram(platform);
 }
 
 static void pre_boot(struct platform *p, const struct config *config)
@@ -1327,7 +757,7 @@ static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
 
 	sysinfo->bmc_mac = talloc_zero_size(sysinfo, HWADDR_SIZE);
 	if (platform->ipmi)
-		get_ipmi_bmc_mac(p, sysinfo->bmc_mac);
+		get_ipmi_bmc_mac(platform->ipmi, sysinfo->bmc_mac, ipmi_timeout);
 
 	if (platform->ipmi)
 		get_ipmi_bmc_versions(p, sysinfo);
@@ -1357,6 +787,7 @@ static bool probe(struct platform *p, void *ctx)
 	list_init(&platform->params);
 
 	p->platform_data = platform;
+	p->get_params_list = get_params_list;
 
 	bmc_present = stat("/proc/device-tree/bmc", &statbuf) == 0;
 
@@ -1381,7 +812,6 @@ static bool probe(struct platform *p, void *ctx)
 	return true;
 }
 
-
 static struct platform platform_powerpc = {
 	.name			= "powerpc",
 	.dhcp_arch_id		= 0x000e,
diff --git a/discover/platform.c b/discover/platform.c
index cc6306f035b9..f8e4646fd3f7 100644
--- a/discover/platform.c
+++ b/discover/platform.c
@@ -3,7 +3,9 @@
 
 #include <fcntl.h>
 #include <string.h>
+#include <stdlib.h>
 #include <locale.h>
+#include <limits.h>
 
 #include <log/log.h>
 #include <file/file.h>
@@ -11,11 +13,27 @@
 #include <talloc/talloc.h>
 
 #include "platform.h"
+#include <url/url.h>
 
 void			*platform_ctx;
 static struct platform	*platform;
 static struct config	*config;
 
+const char *known_params[] = {
+	"auto-boot?",
+	"petitboot,network",
+	"petitboot,timeout",
+	"petitboot,bootdevs",
+	"petitboot,language",
+	"petitboot,debug?",
+	"petitboot,write?",
+	"petitboot,snapshots?",
+	"petitboot,console",
+	"petitboot,http_proxy",
+	"petitboot,https_proxy",
+	NULL,
+};
+
 static const char *kernel_cmdline_debug = "petitboot.debug";
 
 static void dump_config(struct config *config)
@@ -121,7 +139,6 @@ void config_set_defaults(struct config *config)
 
 	config->autoboot_enabled = true;
 	config->autoboot_timeout_sec = 10;
-	config->autoboot_enabled = true;
 	config->network.interfaces = NULL;
 	config->network.n_interfaces = 0;
 	config->network.dns_servers = NULL;
@@ -158,6 +175,555 @@ void config_set_defaults(struct config *config)
 
 }
 
+static struct list *get_platform_params(struct platform *p)
+{
+	if (p->get_params_list)
+		return p->get_params_list(p);
+
+	return NULL;
+}
+
+static const char *get_param(struct list *platform_params, const char *name)
+{
+	struct params*param;
+
+	list_for_each_entry(platform_params, param, list)
+		if (!strcmp(param->name, name))
+			return param->value;
+	return NULL;
+}
+
+static void set_param(void *ctx, struct list *platform_params,
+		const char *name, const char *value)
+{
+	struct params*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(ctx, struct params);
+	param->modified = true;
+	param->name = talloc_strdup(ctx, name);
+	param->value = talloc_strdup(ctx, value);
+	list_add(platform_params, &param->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, *tok_gw, *tok_url, *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);
+
+		/*
+		 * If a url is set but not a gateway, we can accidentally
+		 * interpret the url as the gateway. To avoid changing the
+		 * parameter format check if the "gateway" is actually a
+		 * pb-url if it's the last token.
+		 */
+		tok_gw = strtok_r(NULL, ",", &saveptr);
+		tok_url = strtok_r(NULL, ",", &saveptr);
+
+		if (tok_gw) {
+			if (tok_url || !is_url(tok_gw))
+				ifconf->static_config.gateway =
+					talloc_strdup(ifconf, tok_gw);
+			else
+					tok_url = tok_gw;
+		}
+
+		if (tok_url)
+			ifconf->static_config.url =
+				talloc_strdup(ifconf, tok_url);
+	} 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 list *platform_params,
+		struct config *config)
+{
+	char *val, *saveptr = NULL;
+	const char *cval;
+	int i;
+
+	cval = get_param(platform_params, "petitboot,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 list *platform_params,
+		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_params, "petitboot,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;
+}
+
+void populate_config(struct list *platform_params, 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_params, "auto-boot?");
+	config->autoboot_enabled = !val || strcmp(val, "false");
+
+	val = get_param(platform_params, "petitboot,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_params, "petitboot,language");
+	config->lang = val ? talloc_strdup(config, val) : NULL;
+
+	populate_network_config(platform_params, config);
+
+	populate_bootdev_config(platform_params, config);
+
+	if (!config->debug) {
+		val = get_param(platform_params, "petitboot,debug?");
+		config->debug = val && !strcmp(val, "true");
+	}
+
+	val = get_param(platform_params, "petitboot,write?");
+	if (val)
+		config->allow_writes = !strcmp(val, "true");
+
+	val = get_param(platform_params, "petitboot,snapshots?");
+	if (val)
+		config->disable_snapshots = !strcmp(val, "false");
+
+	val = get_param(platform_params, "petitboot,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_params, "petitboot,http_proxy");
+	if (val)
+		config->http_proxy = talloc_strdup(config, val);
+	val = get_param(platform_params, "petitboot,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(void *ctx, struct list *platform_params,
+		const char *name, const char *value)
+{
+	const char *cur;
+
+	cur = get_param(platform_params, name);
+
+	/* don't set an empty parameter if it doesn't already exist */
+	if (!cur && !strlen(value))
+		return;
+
+	set_param(ctx, platform_params, name, value);
+}
+
+void update_network_config(struct list *platform_params, 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(config, "");
+
+	for (i = 0; i < config->network.n_interfaces; i++) {
+		char *iface_str = iface_config_str(config,
+					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(config,
+						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(config, platform_params, "petitboot,network", val);
+
+	talloc_free(val);
+}
+
+static void update_bootdev_config(struct list *platform_params,
+		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(config, platform_params, "petitboot,bootdevs", val);
+	talloc_free(tmp);
+	if (boot_str)
+		talloc_free(boot_str);
+}
+
+int update_config(struct platform *p, struct config *config,
+		  struct config *defaults)
+{
+	char *tmp = NULL;
+	const char *val;
+	struct list *platform_params;
+
+	platform_params = get_platform_params(p);
+	if (!platform_params)
+		return -1;
+
+	if (config->autoboot_enabled == defaults->autoboot_enabled)
+		val = "";
+	else
+		val = config->autoboot_enabled ? "true" : "false";
+	update_string_config(config, platform_params, "auto-boot?", val);
+
+	if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
+		val = "";
+	else
+		val = tmp = talloc_asprintf(config, "%d",
+				config->autoboot_timeout_sec);
+
+
+	update_string_config(config, platform_params, "petitboot,timeout", val);
+	if (tmp)
+		talloc_free(tmp);
+
+	val = config->lang ?: "";
+	update_string_config(config, platform_params, "petitboot,language", val);
+
+	if (config->allow_writes == defaults->allow_writes)
+		val = "";
+	else
+		val = config->allow_writes ? "true" : "false";
+	update_string_config(config, platform_params, "petitboot,write?", val);
+
+	if (!config->manual_console) {
+		val = config->boot_console ?: "";
+		update_string_config(config, platform_params, "petitboot,console", val);
+	}
+
+	val = config->http_proxy ?: "";
+	update_string_config(config, platform_params, "petitboot,http_proxy", val);
+	val = config->https_proxy ?: "";
+	update_string_config(config, platform_params, "petitboot,https_proxy", val);
+
+	update_network_config(platform_params, config);
+
+	update_bootdev_config(platform_params, config);
+
+	if(platform->update_config)
+		platform->update_config(p, config);
+
+	return 0;
+}
+
+void get_ipmi_bmc_mac(struct ipmi *ipmi, uint8_t *buf, int ipmi_timeout)
+{
+	uint16_t resp_len = 8;
+	uint8_t resp[8];
+	uint8_t req[] = { 0x1, 0x5, 0x0, 0x0 };
+	int i, rc;
+
+	rc = ipmi_transaction(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");
+	}
+
+}
+
 int platform_init(void *ctx)
 {
 	extern struct platform *__start_platforms,  *__stop_platforms;
@@ -209,6 +775,25 @@ int platform_get_sysinfo(struct system_info *info)
 	return -1;
 }
 
+static int save_config(struct platform *platform, struct config *config)
+{
+	struct config *defaults;
+	int rc;
+
+	defaults = talloc_zero(platform_ctx, struct config);
+	config_set_defaults(defaults);
+
+	rc = update_config(platform, config, defaults);
+	if (rc)
+		goto finish;
+
+	rc = platform->save_config(platform);
+
+finish:
+	talloc_free(defaults);
+	return rc;
+}
+
 int config_set(struct config *newconfig)
 {
 	int rc;
@@ -222,7 +807,7 @@ int config_set(struct config *newconfig)
 	pb_log("new configuration data received\n");
 	dump_config(newconfig);
 
-	rc = platform->save_config(platform, newconfig);
+	rc = save_config(platform, newconfig);
 
 	if (!rc)
 		config = talloc_steal(platform_ctx, newconfig);
