diff --git a/discover/Makefile.am b/discover/Makefile.am
index 4a6cbd0..a25622c 100644
--- a/discover/Makefile.am
+++ b/discover/Makefile.am
@@ -76,6 +76,8 @@ discover_pb_discover_CPPFLAGS = \
 discover_platform_ro_SOURCES = \
 	discover/platform.c \
 	discover/platform.h \
+	discover/platform-powerpc-update.c \
+	discover/platform-powerpc-update.h \
 	discover/ipmi.c \
 	discover/ipmi.h \
 	discover/dt.c \
diff --git a/discover/platform-powerpc-update.c b/discover/platform-powerpc-update.c
new file mode 100644
index 0000000..d257bdd
--- /dev/null
+++ b/discover/platform-powerpc-update.c
@@ -0,0 +1,210 @@
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/fcntl.h>
+
+#include <talloc/talloc.h>
+#include <log/log.h>
+#include <process/process.h>
+#include <types/types.h>
+#include <i18n/i18n.h>
+#include <system/system.h>
+#include <url/url.h>
+
+#include "platform-powerpc-update.h"
+
+struct update_data {
+	void		(*status_fn)(void *arg, struct status *status,
+				enum update_status state);
+	void		*status_arg;
+	const char	*nvram_file;
+	enum {
+				PFLASH_UNKNOWN = 0,
+				PFLASH_ERASE,
+				PFLASH_WRITE,
+	} flash_state;
+};
+
+static int pflash_progress_cb(void *arg)
+{
+
+	const char *pflash_fmt = "\r[%*[= ]] %u%% ETA:%8s\n";
+	struct process_info *procinfo = arg;
+	char *line = NULL;
+	unsigned int percentage;
+	struct update_data *data;
+	struct status status;
+	struct process *p;
+	int rc;
+	char eta[9];
+
+	if (!arg)
+		return -1;
+
+	p = procinfo_get_process(procinfo);
+	data = p->stdout_data;
+
+	rc = process_stdout_custom(procinfo, &line);
+
+	if (rc || !line)
+		return rc;
+
+	switch (data->flash_state) {
+	case PFLASH_UNKNOWN:
+		if (strstr(line, "Erasing"))
+			data->flash_state = PFLASH_ERASE;
+		else if (strstr(line, "Programming"))
+			data->flash_state = PFLASH_WRITE;
+		break;
+	case PFLASH_ERASE:
+		if (strstr(line, "Programming"))
+			data->flash_state = PFLASH_WRITE;
+		break;
+	case PFLASH_WRITE:
+		break;
+	}
+
+	rc = sscanf(line, pflash_fmt, &percentage, eta);
+	if (rc != 2) {
+		pb_debug("pflash ??: %s\n", line);
+		talloc_free(line);
+		return 0;
+	}
+
+	status.type = STATUS_INFO;
+	status.message = talloc_asprintf(line,
+			_("Update Progress: %s %u%%, ETA %s\n"),
+			data->flash_state == PFLASH_ERASE ? _("erasing") :
+			data->flash_state == PFLASH_WRITE ? _("writing") : "",
+			percentage, eta);
+	status.backlog = false;
+	data->status_fn(data->status_arg, &status, UPDATE_RUNNING);
+	pb_debug("pflash cb: %u%%, eta %s\n", percentage, eta);
+
+	talloc_free(line);
+	return 0;
+}
+
+/* Restore NVRAM contents after update for flash based update */
+static void nvram_restore_cb(struct process *process)
+{
+	struct update_data *data = process->data;
+	struct status status;
+	int rc;
+
+	pb_log("Update complete!\n");
+
+	if (!process || !process->data)
+		return;
+
+	status.backlog = false;
+
+	if (process->exit_status) {
+		pb_log("pflash returned an error - leaving NVRAM alone\n");
+		status.type = STATUS_ERROR;
+		status.message = talloc_asprintf(data,
+				_("Update failed - check logs for details"));
+		data->status_fn(data->status_arg, &status,
+				UPDATE_ERROR);
+		goto out;
+	}
+
+	rc = process_run_simple(process, pb_system_apps.pflash,
+			"-e", "-f", "-p", data->nvram_file, "-P", "NVRAM",
+			NULL);
+	if (rc) {
+		pb_log("Failed to restore NVRAM!\n");
+		status.type = STATUS_ERROR;
+		status.message = talloc_asprintf(data,
+				_("Failed to restore NVRAM!"));
+		data->status_fn(data->status_arg, &status,
+				UPDATE_ERROR);
+	} else {
+		status.type = STATUS_INFO;
+		status.message = talloc_asprintf(data,
+				_("Update complete! You may now reboot"));
+		data->status_fn(data->status_arg, &status,
+				UPDATE_COMPLETED);
+	}
+
+out:
+	talloc_free(process);
+	talloc_free(data);
+}
+
+int platform_update_flash(void *ctx, struct pb_url *url, const char *file,
+		void (*status_fn)(void *arg, struct status *status,
+			enum update_status state),
+		void *status_arg,
+		const struct system_info *info)
+{
+	struct update_data *data;
+	struct process *process;
+	(void)info;
+	int rc;
+
+	/* Only complete PNOR images accepted */
+	if (!pb_url_check_extension(url, ".pnor")) {
+		pb_log("update: Only .pnor files supported\n");
+		return -1;
+	}
+
+	data = talloc_zero(ctx, struct update_data);
+	if (!data)
+		return -1;
+
+	data->status_fn = status_fn;
+	data->status_arg = status_arg;
+
+	/* Preserve NVRAM partition - will be restored in callback */
+	data->nvram_file = talloc_asprintf(data, "/tmp/pb-nvram");
+	if (!data->nvram_file) {
+		talloc_free(data);
+		return -1;
+	}
+
+	rc = process_run_simple(ctx, pb_system_apps.pflash,
+			"-r", data->nvram_file, "-P", "NVRAM", NULL);
+	if (rc) {
+		pb_log("Failed to preserve NVRAM\n");
+		talloc_free(data);
+		return rc;
+	}
+
+	/* Perform Update */
+	const char *argv[] = {
+		pb_system_apps.pflash,
+		"-e",
+		"-p",
+		file,
+		"-f",
+		NULL
+	};
+
+	process = process_create(ctx);
+	if (!process) {
+		pb_log("update: Failed to create process\n");
+		talloc_free(data);
+		return -1;
+	}
+
+	process->path = pb_system_apps.pflash;
+	process->argv = argv;
+	process->keep_stdout = true;
+	process->stdout_cb = pflash_progress_cb;
+	process->stdout_data = data;
+	process->exit_cb = nvram_restore_cb;
+	process->data = data;
+	rc = process_run_async(process);
+
+	if (rc || process->exit_status) {
+		pb_log("Error updating firmware\n");
+		talloc_free(process);
+		talloc_free(data);
+	}
+
+	return rc;
+}
diff --git a/discover/platform-powerpc-update.h b/discover/platform-powerpc-update.h
new file mode 100644
index 0000000..e629cd5
--- /dev/null
+++ b/discover/platform-powerpc-update.h
@@ -0,0 +1,13 @@
+#ifndef PLATFORM_UPDATE_H
+#define PLATFORM_UPDATE_H
+
+#include "config.h"
+#include <types/types.h>
+
+int platform_update_flash(void *ctx, struct pb_url *url, const char *file,
+		void (*status_fn)(void *arg, struct status *status,
+			enum update_status state),
+		void *status_arg,
+		const struct system_info *info);
+
+#endif /* PLATFORM_UPDATE_H */
diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
index 0e2f87d..4b7ee60 100644
--- a/discover/platform-powerpc.c
+++ b/discover/platform-powerpc.c
@@ -16,11 +16,17 @@
 #include <log/log.h>
 #include <process/process.h>
 #include <types/types.h>
+#include <i18n/i18n.h>
+#include <system/system.h>
+#include <device-tree/device-tree.h>
+#include <pb-config/pb-config.h>
 
 #include "hostboot.h"
 #include "platform.h"
 #include "ipmi.h"
 #include "dt.h"
+#include "device-handler.h"
+#include "platform-powerpc-update.h"
 
 static const char *partition = "common";
 static const char *sysparams_dir = "/sys/firmware/opal/sysparams/";
@@ -47,6 +53,13 @@ struct platform_powerpc {
 	int 		(*set_os_boot_sensor)(
 				struct platform_powerpc *platform);
 	int		(*get_platform_versions)(struct system_info *info);
+	int		(*update)(
+				void *ctx, struct pb_url *url, const char *file,
+				void (*status_fn)(
+					void *arg, struct status *status,
+					enum update_status state),
+				void *status_arg,
+				const struct system_info *info);
 
 	enum {
 			POWERPC_PLATFORM_FSP,
@@ -67,6 +80,8 @@ static const char *known_params[] = {
 	"petitboot,console",
 	"petitboot,http_proxy",
 	"petitboot,https_proxy",
+	"petitboot,metadata_source",
+	"petitboot,platform_update?",
 	NULL,
 };
 
@@ -553,6 +568,14 @@ static void populate_config(struct platform_powerpc *platform,
 	val = get_param(platform, "petitboot,https_proxy");
 	if (val)
 		config->https_proxy = talloc_strdup(config, val);
+
+	val = get_param(platform, "petitboot,metadata_source");
+	if (val)
+		config->metadata_source = talloc_strdup(config, val);
+
+	val = get_param(platform, "petitboot,platform_update?");
+	if (val)
+		config->platform_update = !strcmp(val, "true");
 }
 
 static char *iface_config_str(void *ctx, struct interface_config *config)
@@ -733,6 +756,15 @@ static int update_config(struct platform_powerpc *platform,
 	val = config->https_proxy ?: "";
 	update_string_config(platform, "petitboot,https_proxy", val);
 
+	val = config->metadata_source ?: "";
+	update_string_config(platform, "petitboot,metadata_source", val);
+
+	if (config->platform_update == defaults->platform_update)
+		val = "";
+	else
+		val = config->platform_update ? "true" : "false";
+	update_string_config(platform, "petitboot,platform_update?", val);
+
 	update_network_config(platform, config);
 
 	update_bootdev_config(platform, config);
@@ -1327,8 +1359,15 @@ static void pre_boot(struct platform *p, const struct config *config)
 static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
 {
 	struct platform_powerpc *platform = p->platform_data;
+	struct process *process;
 	char *buf, *filename;
 	int len, rc;
+	const char *argv[] = {
+		pb_system_apps.obmc_update,
+		"check",
+		sysinfo->bmc_ip,
+		NULL,
+	};
 
 	filename = talloc_asprintf(platform, "%smodel", devtree_dir);
 	rc = read_file(platform, filename, &buf, &len);
@@ -1361,9 +1400,29 @@ static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
 		if (platform->get_platform_versions(sysinfo))
 			pb_log("Failed to read platform versions\n");
 
+	if (platform->type == POWERPC_PLATFORM_BMC)
+		platform->update = platform_update_flash;
+	else
+		platform->update = NULL;
+
+	sysinfo->update_support = platform->type == POWERPC_PLATFORM_BMC;
+
 	return 0;
 }
 
+// we could just pass the update_data in here directly
+static int update_platform(struct platform *p, struct pb_url *url,
+		const char *file,
+		void (*status_fn)(void *arg, struct status *status,
+			enum update_status state),
+		void *status_arg, const struct system_info *info)
+{
+	struct platform_powerpc *platform = to_platform_powerpc(p);
+
+	return platform->update(platform, url, file, status_fn, status_arg,
+			info);
+}
+
 static bool probe(struct platform *p, void *ctx)
 {
 	struct platform_powerpc *platform;
@@ -1424,6 +1483,7 @@ static struct platform platform_powerpc = {
 	.save_config		= save_config,
 	.pre_boot		= pre_boot,
 	.get_sysinfo		= get_sysinfo,
+	.update_platform	= update_platform,
 };
 
 register_platform(platform_powerpc);
diff --git a/discover/platform.c b/discover/platform.c
index cc6306f..accc62a 100644
--- a/discover/platform.c
+++ b/discover/platform.c
@@ -94,6 +94,11 @@ static void dump_config(struct config *config)
 
 
 	pb_log(" language: %s\n", config->lang ?: "");
+
+	pb_log(" metadata source: %s\n", config->metadata_source ?: "");
+	pb_log(" update source: %s\n", config->update_source ?: "");
+	pb_log("  Platform updates allowed: %s\n",
+			config->platform_update ? "yes" : "no");
 }
 
 static bool config_debug_on_cmdline(void)
@@ -131,6 +136,9 @@ void config_set_defaults(struct config *config)
 	config->safe_mode = false;
 	config->allow_writes = true;
 	config->disable_snapshots = false;
+	config->metadata_source = NULL;
+	config->update_source = NULL;
+	config->platform_update = false;
 
 	config->n_consoles = 0;
 	config->consoles = NULL;
@@ -202,6 +210,17 @@ void platform_pre_boot(void)
 		platform->pre_boot(platform, config);
 }
 
+int platform_update(struct pb_url *url, const char *file,
+		void (*status_fn)(void *arg, struct status *status,
+			enum update_status state),
+		void *status_arg, const struct system_info *info)
+{
+	if (platform && platform->update_platform)
+		return platform->update_platform(platform, url, file, status_fn,
+				status_arg, info);
+	return -1;
+}
+
 int platform_get_sysinfo(struct system_info *info)
 {
 	if (platform && platform->get_sysinfo)
diff --git a/discover/platform.h b/discover/platform.h
index 5aa8e3f..6a3e108 100644
--- a/discover/platform.h
+++ b/discover/platform.h
@@ -2,6 +2,7 @@
 #define PLATFORM_H
 
 #include <types/types.h>
+#include "paths.h"
 
 struct platform {
 	const char	*name;
@@ -11,6 +12,13 @@ struct platform {
 	void		(*pre_boot)(struct platform *,
 				const struct config *);
 	int		(*get_sysinfo)(struct platform *, struct system_info *);
+	int		(*update_platform)(struct platform *p,
+				struct pb_url *url, const char *file,
+				void (*status_fn)(void *arg,
+					struct status *status,
+					enum update_status state),
+				void *status_arg,
+				const struct system_info *info);
 	uint16_t	dhcp_arch_id;
 	void		*platform_data;
 };
@@ -20,6 +28,10 @@ int platform_fini(void);
 const struct platform *platform_get(void);
 int platform_get_sysinfo(struct system_info *info);
 void platform_pre_boot(void);
+int platform_update(struct pb_url *url, const char *file,
+		void (*status_fn)(void *arg, struct status *status,
+			enum update_status state),
+		void *status_arg, const struct system_info *info);
 
 /* configuration interface */
 const struct config *config_get(void);
