aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/external/pflash
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/external/pflash')
-rw-r--r--roms/skiboot/external/pflash/.gitignore6
-rw-r--r--roms/skiboot/external/pflash/Makefile48
-rw-r--r--roms/skiboot/external/pflash/Makefile.dist11
-rw-r--r--roms/skiboot/external/pflash/TODO5
-rwxr-xr-xroms/skiboot/external/pflash/build-all-arch.sh35
-rw-r--r--roms/skiboot/external/pflash/config.h24
-rw-r--r--roms/skiboot/external/pflash/pflash.196
-rw-r--r--roms/skiboot/external/pflash/pflash.c1230
-rw-r--r--roms/skiboot/external/pflash/progress.c92
-rw-r--r--roms/skiboot/external/pflash/progress.h15
-rw-r--r--roms/skiboot/external/pflash/rules.mk57
-rw-r--r--roms/skiboot/external/pflash/test/files/01-info.ffs6
-rw-r--r--roms/skiboot/external/pflash/test/files/02-erase.ffs4
-rw-r--r--roms/skiboot/external/pflash/test/files/03-erase-parts.ffs4
-rw-r--r--roms/skiboot/external/pflash/test/files/04-program-rand.ffs4
-rw-r--r--roms/skiboot/external/pflash/test/files/05-bad-numbers.ffs4
-rw-r--r--roms/skiboot/external/pflash/test/files/06-miscprint.ffs6
-rwxr-xr-xroms/skiboot/external/pflash/test/make-check-test1
-rw-r--r--roms/skiboot/external/pflash/test/results/00-usage.err0
-rw-r--r--roms/skiboot/external/pflash/test/results/00-usage.out114
-rw-r--r--roms/skiboot/external/pflash/test/results/01-info.err0
-rw-r--r--roms/skiboot/external/pflash/test/results/01-info.out15
-rw-r--r--roms/skiboot/external/pflash/test/results/02-erase.err0
-rw-r--r--roms/skiboot/external/pflash/test/results/02-erase.out105
-rw-r--r--roms/skiboot/external/pflash/test/results/03-erase-parts.err0
-rw-r--r--roms/skiboot/external/pflash/test/results/03-erase-parts.out106
-rw-r--r--roms/skiboot/external/pflash/test/results/04-program-rand.err0
-rw-r--r--roms/skiboot/external/pflash/test/results/04-program-rand.out111
-rw-r--r--roms/skiboot/external/pflash/test/results/05-bad-numbers.err0
-rw-r--r--roms/skiboot/external/pflash/test/results/05-bad-numbers.out224
-rw-r--r--roms/skiboot/external/pflash/test/results/06-miscprint.err0
-rw-r--r--roms/skiboot/external/pflash/test/results/06-miscprint.out54
-rwxr-xr-xroms/skiboot/external/pflash/test/test-pflash59
-rw-r--r--roms/skiboot/external/pflash/test/tests/00-usage13
-rw-r--r--roms/skiboot/external/pflash/test/tests/01-info23
-rw-r--r--roms/skiboot/external/pflash/test/tests/02-erase27
-rw-r--r--roms/skiboot/external/pflash/test/tests/03-erase-parts56
-rw-r--r--roms/skiboot/external/pflash/test/tests/04-program-rand55
-rw-r--r--roms/skiboot/external/pflash/test/tests/05-bad-numbers66
-rw-r--r--roms/skiboot/external/pflash/test/tests/06-miscprint46
40 files changed, 2722 insertions, 0 deletions
diff --git a/roms/skiboot/external/pflash/.gitignore b/roms/skiboot/external/pflash/.gitignore
new file mode 100644
index 000000000..223b639e8
--- /dev/null
+++ b/roms/skiboot/external/pflash/.gitignore
@@ -0,0 +1,6 @@
+ccan
+common
+libflash
+make_version.sh
+pflash
+test/test.sh
diff --git a/roms/skiboot/external/pflash/Makefile b/roms/skiboot/external/pflash/Makefile
new file mode 100644
index 000000000..2918b7c3d
--- /dev/null
+++ b/roms/skiboot/external/pflash/Makefile
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: Apache-2.0
+include rules.mk
+GET_ARCH := ../../external/common/get_arch.sh
+include ../../external/common/rules.mk
+
+all: links arch_links $(EXE)
+
+.PHONY: coverage
+coverage: CFLAGS += -fprofile-arcs -ftest-coverage
+coverage: check
+
+#Rebuild version.o so that the the version always matches
+#what the test suite will get from ./make_version.sh
+check: version.o all
+ $(MAKE) -C ../ffspart
+ @ln -sf ../../make_version.sh make_version.sh
+ @ln -sf ../../test/test.sh test/test.sh
+ @test/test-pflash
+
+.PHONY: VERSION-always
+.version: VERSION-always
+ @echo $(PFLASH_VERSION) > $@.tmp
+ @cmp -s $@ $@.tmp || cp $@.tmp $@
+ @rm -f $@.tmp
+
+install: all $(INSTALLDEPS)
+ install -D pflash $(DESTDIR)$(sbindir)/pflash
+ install -D -m 0644 pflash.1 $(DESTDIR)$(mandir)/man1/pflash.1
+
+.PHONY: dist
+#File is named $(PFLASH_VERSION).tar because the expectation is that pflash-
+#is always at the start of the verion. This remains consistent with skiboot
+#version strings
+dist: links .version
+ find -L ../pflash/ -iname '*.[ch]' -print0 | xargs -0 tar -rhf $(PFLASH_VERSION).tar
+ tar --transform 's/Makefile.dist/Makefile/' -rhf $(PFLASH_VERSION).tar \
+ ../pflash/Makefile.dist ../pflash/rules.mk \
+ ../pflash/.version ../pflash/make_version.sh \
+ ../pflash/common/*
+
+.PHONY: clean
+clean: arch_clean
+ rm -f $(OBJS) $(EXE) *.o *.d
+.PHONY: distclean
+distclean: clean
+ rm -f *.c~ *.h~ *.sh~ Makefile~ config.mk~ libflash/*.c~ libflash/*.h~
+ rm -f libflash ccan version.c .version .version.tmp
+ rm -f common io.h
diff --git a/roms/skiboot/external/pflash/Makefile.dist b/roms/skiboot/external/pflash/Makefile.dist
new file mode 100644
index 000000000..85e41fa64
--- /dev/null
+++ b/roms/skiboot/external/pflash/Makefile.dist
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+include rules.mk
+GET_ARCH = common/get_arch.sh
+include common/rules.mk
+
+all: $(EXE)
+
+clean:
+ rm -f $(OBJS) *.o
+distclean: clean
+ rm -f $(EXE)
diff --git a/roms/skiboot/external/pflash/TODO b/roms/skiboot/external/pflash/TODO
new file mode 100644
index 000000000..a632c3891
--- /dev/null
+++ b/roms/skiboot/external/pflash/TODO
@@ -0,0 +1,5 @@
+- PCI backend for host
+- Use proper GPIO APIs on ARM
+- Use IPMI for lock/unlock on host
+- Timeouts and flashing errors handling
+- Lock handling
diff --git a/roms/skiboot/external/pflash/build-all-arch.sh b/roms/skiboot/external/pflash/build-all-arch.sh
new file mode 100755
index 000000000..14364334a
--- /dev/null
+++ b/roms/skiboot/external/pflash/build-all-arch.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# Script to build all pflash backends
+#
+# Copyright 2015 IBM Corp.
+#
+# pflash has three different backends that are used on powerpc, arm (BMC) and
+# x86 (file-backed). In order to test for regressions when touching shared code
+# such as libflash.
+#
+# Defaults to the cross compilers available under Ubuntu. You can set the
+# environment variables arm_cc, amd64_cc, ppc64le_cc for other distributions.
+#
+# installing on x86:
+# apt-get install gcc-arm-linux-gnueabi gcc-powerpc64le-linux-gnu gcc
+#
+
+arm_cc=${arm_cc:-arm-linux-gnueabi-}
+amd64_cc=${amd64_cc:-x86_64-linux-gnu-}
+ppc64le_cc=${ppc64le_cc:-powerpc64le-linux-gnu-}
+
+echo "Building for ARM..."
+make clean && make distclean
+CROSS_COMPILE=${arm_cc} make || { echo "ARM build failed"; exit 1; }
+
+echo "Building for x86..."
+make clean && make distclean
+CROSS_COMPILE=${amd64_cc} make || { echo "x86 build failed"; exit 1; }
+
+echo "Building for ppc64le..."
+make clean && make distclean
+CROSS_COMPILE=${ppc64le_cc} make || { echo "ppc64le build failed"; exit 1; }
+
+make clean && make distclean
diff --git a/roms/skiboot/external/pflash/config.h b/roms/skiboot/external/pflash/config.h
new file mode 100644
index 000000000..34da2eb7c
--- /dev/null
+++ b/roms/skiboot/external/pflash/config.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * For CCAN
+ *
+ * Copyright 2014 IBM Corp.
+ */
+
+#include <endian.h>
+#include <byteswap.h>
+
+#define HAVE_TYPEOF 1
+#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1
+
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define HAVE_BIG_ENDIAN 0
+#define HAVE_LITTLE_ENDIAN 1
+#else
+#define HAVE_BIG_ENDIAN 1
+#define HAVE_LITTLE_ENDIAN 0
+#endif
+
+#define HAVE_BYTESWAP_H 1
+#define HAVE_BSWAP_64 1
diff --git a/roms/skiboot/external/pflash/pflash.1 b/roms/skiboot/external/pflash/pflash.1
new file mode 100644
index 000000000..5db8d4609
--- /dev/null
+++ b/roms/skiboot/external/pflash/pflash.1
@@ -0,0 +1,96 @@
+.TH pflash "1" "September 2016"
+.SH NAME
+pflash \- manual page for Open-Power Flash tool
+.SH SYNOPSIS
+\fBpflash\fP [\fI\,options\/\fP] \fI\,commands\/\fP...
+.SH DESCRIPTION
+pflash is a tool to access the flash modules
+on such systems and update the OpenPower firmware.
+.SS Options
+.TP
+\fB\-a\fP \fI\,address\/\fP, \fB\-\-address\fP=\fI\,address\/\fP
+Specify the start address for erasing, reading or flashing
+.TP
+\fB\-s\fP \fI\,size\/\fP, \fB\-\-size\fP=\fI\,size\/\fP
+Specify the size in bytes for erasing, reading or flashing
+.TP
+\fB\-P\fP \fI\,part_name\/\fP, \fB\-\-partition\fP=\fI\,part_name\/\fP
+Specify the partition whose content is to be erased
+programmed or read. This is an alternative to \fB\-a\fP and \fB\-s\fP
+if both \fB\-P\fP and \fB\-s\fP are specified, the smallest of the
+two will be used
+.TP
+\fB\-f\fP, \fB\-\-force\fP
+Don't ask for confirmation before erasing or flashing
+.TP
+\fB\-d\fP, \fB\-\-dummy\fP
+Don't write to flash
+.TP
+\fB\-m\fP, \fB\-\-mtd\fP
+Avoid accessing the flash directly if the BMC supports it.
+This will access the flash through the kernel MTD layer and
+not the flash directly
+.TP
+\fB\-b\fP, \fB\-\-bmc\fP
+Target BMC flash instead of host flash.
+Note: This carries a high chance of bricking your BMC if you
+don't know what you're doing. Consider \fB\-\-mtd\fP to be safe(r)
+.TP
+\fB\-F\fP \fI\,filename\/\fP, \fB\-\-flash\-file\fP \fI\,filename
+Target filename instead of actual flash.
+.TP
+\fB\-S\fP, \fB\-\-side\fP
+Side of the flash on which to operate, 0 (default) or 1
+.TP
+\fB\-T\fP, \fB\-\-toc\fP
+libffs TOC on which to operate, defaults to 0.
+leading 0x is required for interpretation of a hex value
+.SS
+Commands:
+.TP
+\fB\-4\fP, \fB\-\-enable\-4B\fP
+Switch the flash and controller to 4\-bytes address
+mode (no confirmation needed).
+.TP
+\fB\-3\fP, \fB\-\-disable\-4B\fP
+Switch the flash and controller to 3\-bytes address
+mode (no confirmation needed).
+.TP
+\fB\-r\fP \fI\,file\/\fP, \fB\-\-read\fP=\fI\,file\/\fP
+Read flash content from address into file, use \fB\-s\fP
+to specify the size to read (or it will use the source
+file size if used in conjunction with \fB\-p\fP and \fB\-s\fP is not
+specified). When using \fB\-r\fP together with \fB\-e\fP or \fB\-p\fP, the
+read will be performed first
+.TP
+\fB\-E\fP, \fB\-\-erase\-all\fP
+Erase entire flash chip (Not supported on all chips/controllers)
+.TP
+\fB\-e\fP, \fB\-\-erase\fP
+Erase the specified region. If size or address are not
+specified, but '\-\-program' is used, then the file
+size will be used (rounded to an erase block) and the
+address defaults to 0.
+.TP
+\fB\-p\fP \fI\,file\/\fP, \fB\-\-program\fP=\fI\,file\/\fP
+Will program the file to flash. If the address is not
+specified, it will use 0. If the size is not specified
+it will use the file size. Otherwise it will limit to
+the specified size (whatever is smaller). If used in
+conjunction with any erase command, the erase will
+take place first.
+.TP
+\fB\-t\fP, \fB\-\-tune\fP
+Just tune the flash controller & access size
+(Implicit for all other operations)
+.TP
+\fB\-c\fP \fB\-\-clear\fP
+Used to ECC clear a partition of the flash
+Must be used in conjunction with \fB\-P\fP. Will erase the
+partition and then set all the ECC bits as they should be
+.TP
+\fB\-i\fP, \fB\-\-info\fP
+Display some information about the flash.
+.TP
+\fB\-h\fP, \fB\-\-help\fP
+This message.
diff --git a/roms/skiboot/external/pflash/pflash.c b/roms/skiboot/external/pflash/pflash.c
new file mode 100644
index 000000000..8aa2acb1d
--- /dev/null
+++ b/roms/skiboot/external/pflash/pflash.c
@@ -0,0 +1,1230 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Display progress bars, while also writing whole or part
+ * of flash.
+ *
+ * Copyright 2013-2019 IBM Corp.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <getopt.h>
+#include <limits.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include <libflash/libflash.h>
+#include <libflash/libffs.h>
+#include <libflash/blocklevel.h>
+#include <libflash/ecc.h>
+#include <common/arch_flash.h>
+#include "progress.h"
+
+#define __aligned(x) __attribute__((aligned(x)))
+
+struct flash_details {
+ struct blocklevel_device *bl;
+ int need_relock;
+ const char *name;
+ uint64_t toc;
+ uint64_t total_size;
+ uint32_t erase_granule;
+ bool mark_ecc;
+};
+
+/* Full pflash version number (possibly includes gitid). */
+extern const char version[];
+
+const char *flashfilename = NULL;
+static bool must_confirm = true;
+static bool dummy_run;
+static bool bmc_flash;
+
+#define FILE_BUF_SIZE 0x10000
+static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);
+
+static bool check_confirm(void)
+{
+ char yes[8], *p;
+
+ if (!must_confirm)
+ return true;
+
+ printf("WARNING ! This will modify your %s flash chip content !\n",
+ bmc_flash ? "BMC" : "HOST");
+ printf("Enter \"yes\" to confirm:");
+ memset(yes, 0, sizeof(yes));
+ if (!fgets(yes, 7, stdin))
+ return false;
+ p = strchr(yes, 10);
+ if (p)
+ *p = 0;
+ p = strchr(yes, 13);
+ if (p)
+ *p = 0;
+ if (strcmp(yes, "yes")) {
+ printf("Operation cancelled !\n");
+ return false;
+ }
+ must_confirm = false;
+ return true;
+}
+
+static uint32_t print_ffs_info(struct ffs_handle *ffsh, uint32_t toc)
+{
+ struct ffs_entry *ent;
+ uint32_t next_toc = toc;
+ int rc;
+ int i;
+
+ printf("\n");
+ printf("TOC@0x%08x Partitions:\n", toc);
+ printf("-----------\n");
+
+ for (i = 0;; i++) {
+ uint32_t start, size, act, end;
+ struct ffs_entry_user user;
+ char *name = NULL, *flags;
+
+ rc = ffs_part_info(ffsh, i, &name, &start, &size, &act, NULL);
+ if (rc == FFS_ERR_PART_NOT_FOUND)
+ break;
+
+ ent = ffs_entry_get(ffsh, i);
+ if (rc || !ent) {
+ fprintf(stderr, "Error %d scanning partitions\n",
+ !ent ? FFS_ERR_PART_NOT_FOUND : rc);
+ goto out;
+ }
+
+ user = ffs_entry_user_get(ent);
+ ffs_entry_put(ent);
+ flags = ffs_entry_user_to_string(&user);
+ if (!flags)
+ goto out;
+
+ end = start + size;
+ printf("ID=%02d %15s 0x%08x..0x%08x (actual=0x%08x) [%s]\n",
+ i, name, start, end, act, flags);
+
+ if (strcmp(name, "OTHER_SIDE") == 0)
+ next_toc = start;
+
+ free(flags);
+out:
+ free(name);
+ }
+
+ return next_toc;
+}
+
+static struct ffs_handle *open_ffs(struct flash_details *flash)
+{
+ struct ffs_handle *ffsh;
+ int rc;
+
+ rc = ffs_init(flash->toc, flash->total_size,
+ flash->bl, &ffsh, flash->mark_ecc);
+ if (rc) {
+ fprintf(stderr, "Error %d opening ffs !\n", rc);
+ if (flash->toc) {
+ fprintf(stderr, "You specified 0x%" PRIx64 " as the libffs TOC\n"
+ "Looks like it doesn't exist\n", flash->toc);
+ return NULL;
+ }
+ }
+
+ return ffsh;
+}
+
+static void print_flash_info(struct flash_details *flash)
+{
+ struct ffs_handle *ffsh;
+ uint32_t next_toc;
+ uint32_t toc;
+
+ printf("Flash info:\n");
+ printf("-----------\n");
+ printf("Name = %s\n", flash->name);
+ printf("Total size = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED, R:READONLY, "
+ "B:BACKUP\n", flash->total_size >> 20);
+ printf("Erase granule = %2d%-13sF:REPROVISION, V:VOLATILE, C:CLEARECC\n",
+ flash->erase_granule >> 10, "KB");
+
+ if (bmc_flash)
+ return;
+
+ toc = flash->toc;
+
+ ffsh = open_ffs(flash);
+ if (!ffsh)
+ return;
+
+ next_toc = print_ffs_info(ffsh, toc);
+ ffs_close(ffsh);
+ while(next_toc != toc) {
+ struct ffs_handle *next_ffsh;
+
+ flash->toc = next_toc;
+ next_ffsh = open_ffs(flash);
+ if (!next_ffsh)
+ break;
+ next_toc = print_ffs_info(next_ffsh, next_toc);
+ ffs_close(next_ffsh);
+ }
+ flash->toc = toc;
+}
+
+static struct ffs_handle *open_partition(struct flash_details *flash,
+ const char *name, uint32_t *index)
+{
+ struct ffs_handle *ffsh;
+ int rc;
+
+ ffsh = open_ffs(flash);
+ if (!ffsh)
+ return NULL;
+
+ if (!name)
+ /* Just open the FFS */
+ return ffsh;
+
+ /* Find partition */
+ rc = ffs_lookup_part(ffsh, name, index);
+ if (rc == FFS_ERR_PART_NOT_FOUND) {
+ fprintf(stderr, "Partition '%s' not found !\n", name);
+ goto out;
+ }
+ if (rc) {
+ fprintf(stderr, "Error %d looking for partition '%s' !\n",
+ rc, name);
+ goto out;
+ }
+ return ffsh;
+out:
+ ffs_close(ffsh);
+ return NULL;
+}
+
+static struct ffs_handle *lookup_partition_at_toc(struct flash_details *flash,
+ const char *name, uint32_t *index)
+{
+ return open_partition(flash, name, index);
+}
+
+static struct ffs_handle *lookup_partition_at_side(struct flash_details *flash,
+ int side, const char *name, uint32_t *index)
+{
+ uint32_t toc = 0;
+ int rc;
+
+ if (side == 1) {
+ struct ffs_handle *ffsh;
+ uint32_t side_index;
+
+ ffsh = open_partition(flash, "OTHER_SIDE", &side_index);
+ if (!ffsh)
+ return NULL;
+
+ /* Just need to know where it starts */
+ rc = ffs_part_info(ffsh, side_index, NULL, &toc, NULL, NULL, NULL);
+ ffs_close(ffsh);
+ if (rc)
+ return NULL;
+ }
+
+ flash->toc = toc;
+ return lookup_partition_at_toc(flash, name, index);
+}
+
+static int erase_chip(struct flash_details *flash)
+{
+ bool confirm;
+ int rc;
+ uint64_t pos;
+
+ printf("About to erase chip !\n");
+ confirm = check_confirm();
+ if (!confirm)
+ return 1;
+
+ printf("Erasing... (may take a while)\n");
+ fflush(stdout);
+
+ if (dummy_run) {
+ printf("skipped (dummy)\n");
+ return 1;
+ }
+
+ /*
+ * We could use arch_flash_erase_chip() here BUT everyone really
+ * likes the progress bars.
+ * Lets do an erase block at a time erase then...
+ */
+ progress_init(flash->total_size);
+ for (pos = 0; pos < flash->total_size; pos += flash->erase_granule) {
+ rc = blocklevel_erase(flash->bl, pos, flash->erase_granule);
+ if (rc)
+ break;
+ progress_tick(pos);
+ }
+ progress_end();
+ if (rc) {
+ fprintf(stderr, "Error %d erasing chip\n", rc);
+ return rc;
+ }
+
+ printf("done !\n");
+ return 0;
+}
+
+static int erase_range(struct flash_details *flash,
+ uint32_t start, uint32_t size, bool will_program,
+ struct ffs_handle *ffsh, int ffs_index)
+{
+ uint32_t done = 0, erase_mask = flash->erase_granule - 1;
+ struct ffs_entry *toc;
+ bool confirm;
+ int rc;
+
+ printf("About to erase 0x%08x..0x%08x !\n", start, start + size);
+ confirm = check_confirm();
+ if (!confirm)
+ return 1;
+
+ if (dummy_run) {
+ printf("skipped (dummy)\n");
+ return 1;
+ }
+
+ printf("Erasing...\n");
+ /*
+ * blocklevel_smart_erase() can do the entire thing in one call
+ * BUT everyone really likes progress bars so break stuff up
+ */
+ progress_init(size);
+ if (start & erase_mask) {
+ /*
+ * Align to next erase block, or just do the entire
+ * thing if we fit within one erase block
+ */
+ uint32_t first_size = MIN(size, (flash->erase_granule - (start & erase_mask)));
+
+ rc = blocklevel_smart_erase(flash->bl, start, first_size);
+ if (rc) {
+ fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
+ return 1;
+ }
+ size -= first_size;
+ done = first_size;
+ start += first_size;
+ }
+ progress_tick(done);
+ while (size & ~(erase_mask)) {
+ rc = blocklevel_smart_erase(flash->bl, start, flash->erase_granule);
+ if (rc) {
+ fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
+ return 1;
+ }
+ start += flash->erase_granule;
+ size -= flash->erase_granule;
+ done += flash->erase_granule;
+ progress_tick(done);
+ }
+ if (size) {
+ rc = blocklevel_smart_erase(flash->bl, start, size);
+ if (rc) {
+ fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
+ return 1;
+ }
+ done += size;
+ progress_tick(done);
+ }
+ progress_end();
+
+ if (!ffsh)
+ return 0;
+
+ /* If this is a flash partition, mark it empty if we aren't
+ * going to program over it as well
+ */
+ toc = ffs_entry_get(ffsh, 0);
+ if (toc) {
+ struct ffs_entry_user user;
+ bool rw_toc;
+
+ user = ffs_entry_user_get(toc);
+ rw_toc = !(user.miscflags & FFS_MISCFLAGS_READONLY);
+ if (ffs_index >= 0 && !will_program && rw_toc) {
+ printf("Updating actual size in partition header...\n");
+ ffs_update_act_size(ffsh, ffs_index, 0);
+ }
+ }
+
+ return 0;
+}
+
+static int set_ecc(struct flash_details *flash, uint32_t start, uint32_t size)
+{
+ uint32_t i = start + 8;
+ uint8_t ecc = 0;
+ bool confirm;
+ int rc;
+
+ printf("About to erase and set ECC bits in region 0x%08x to 0x%08x\n", start, start + size);
+ confirm = check_confirm();
+ if (!confirm)
+ return 1;
+
+ rc = erase_range(flash, start, size, true, NULL, 0);
+ if (rc) {
+ fprintf(stderr, "Couldn't erase region to mark with ECC\n");
+ return rc;
+ }
+
+ printf("Programming ECC bits...\n");
+ progress_init(size);
+ while (i < start + size) {
+ rc = blocklevel_write(flash->bl, i, &ecc, sizeof(ecc));
+ if (rc) {
+ fprintf(stderr, "\nError setting ECC byte at 0x%08x\n", i);
+ return rc;
+ }
+ i += 9;
+ progress_tick(i - start);
+ }
+ progress_end();
+ return 0;
+}
+
+static int program_file(struct blocklevel_device *bl,
+ const char *file, uint32_t start, uint32_t size,
+ struct ffs_handle *ffsh, int ffs_index)
+{
+ uint32_t actual_size = 0;
+ struct ffs_entry *toc;
+ int fd, rc = 0;
+ bool confirm;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ perror("Failed to open file");
+ return 1;
+ }
+ printf("About to program \"%s\" at 0x%08x..0x%08x !\n",
+ file, start, start + size);
+ confirm = check_confirm();
+ if (!confirm) {
+ rc = 1;
+ goto out;
+ }
+
+ if (dummy_run) {
+ printf("skipped (dummy)\n");
+ rc = 1;
+ goto out;
+ }
+
+ printf("Programming & Verifying...\n");
+ progress_init(size);
+ while(size) {
+ ssize_t len;
+
+ len = read(fd, file_buf, FILE_BUF_SIZE);
+ if (len < 0) {
+ perror("Error reading file");
+ rc = 1;
+ goto out;
+ }
+ if (len == 0)
+ break;
+ if (len > size)
+ len = size;
+ size -= len;
+ actual_size += len;
+ rc = blocklevel_write(bl, start, file_buf, len);
+ if (rc) {
+ if (rc == FLASH_ERR_VERIFY_FAILURE)
+ fprintf(stderr, "Verification failed for"
+ " chunk at 0x%08x\n", start);
+ else
+ fprintf(stderr, "Flash write error %d for"
+ " chunk at 0x%08x\n", rc, start);
+ goto out;
+ }
+ start += len;
+ progress_tick(actual_size);
+ }
+ progress_end();
+
+ if (!ffsh)
+ goto out;
+
+ /* If this is a flash partition, adjust its size */
+ toc = ffs_entry_get(ffsh, 0);
+ if (toc) {
+ struct ffs_entry_user user;
+ bool rw_toc;
+
+ user = ffs_entry_user_get(toc);
+ rw_toc = !(user.miscflags & FFS_MISCFLAGS_READONLY);
+ if (ffs_index >= 0 && rw_toc) {
+ printf("Updating actual size in partition header...\n");
+ ffs_update_act_size(ffsh, ffs_index, actual_size);
+ }
+ }
+out:
+ close(fd);
+ return rc;
+}
+
+static int do_read_file(struct blocklevel_device *bl, const char *file,
+ uint32_t start, uint32_t size, uint32_t skip_size)
+{
+ int fd, rc = 0;
+ uint32_t done = 0;
+
+ fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 00666);
+ if (fd == -1) {
+ perror("Failed to open file");
+ return 1;
+ }
+ start += skip_size;
+ size -= skip_size;
+
+ printf("Reading to \"%s\" from 0x%08x..0x%08x !\n",
+ file, start, start + size);
+
+ progress_init(size);
+ while(size) {
+ ssize_t len;
+
+ len = size > FILE_BUF_SIZE ? FILE_BUF_SIZE : size;
+ rc = blocklevel_read(bl, start, file_buf, len);
+ if (rc) {
+ fprintf(stderr, "Flash read error %d for"
+ " chunk at 0x%08x\n", rc, start);
+ break;
+ }
+ rc = write(fd, file_buf, len);
+ /*
+ * zero isn't strictly an error.
+ * Treat it as such so we can be sure we'lre always
+ * making forward progress.
+ */
+ if (rc <= 0) {
+ perror("Error writing file");
+ break;
+ }
+ start += rc;
+ size -= rc;
+ done += rc;
+ progress_tick(done);
+ }
+ progress_end();
+ close(fd);
+ return size ? rc : 0;
+}
+
+static int enable_4B_addresses(struct blocklevel_device *bl)
+{
+ int rc;
+
+ printf("Switching to 4-bytes address mode\n");
+
+ rc = arch_flash_4b_mode(bl, true);
+ if (rc) {
+ if (rc == -1) {
+ fprintf(stderr, "Switching address mode not available on this architecture\n");
+ } else {
+ fprintf(stderr, "Error %d enabling 4b mode\n", rc);
+ }
+ }
+
+ return rc;
+}
+
+static int disable_4B_addresses(struct blocklevel_device *bl)
+{
+ int rc;
+
+ printf("Switching to 3-bytes address mode\n");
+
+ rc = arch_flash_4b_mode(bl, false);
+ if (rc) {
+ if (rc == -1) {
+ fprintf(stderr, "Switching address mode not available on this architecture\n");
+ } else {
+ fprintf(stderr, "Error %d enabling 4b mode\n", rc);
+ }
+ }
+
+ return rc;
+}
+
+static void print_partition_detail(struct ffs_handle *ffsh, uint32_t part_id)
+{
+ uint32_t start, size, act, end;
+ char *ent_name = NULL, *flags;
+ struct ffs_entry *ent;
+ int rc, l;
+
+ rc = ffs_part_info(ffsh, part_id, &ent_name, &start, &size,
+ &act, NULL);
+ if (rc) {
+ fprintf(stderr, "Partition with ID %d doesn't exist error: %d\n",
+ part_id, rc);
+ goto out;
+ }
+
+ ent = ffs_entry_get(ffsh, part_id);
+ if (!ent) {
+ rc = FFS_ERR_PART_NOT_FOUND;
+ fprintf(stderr, "Couldn't open partition entry\n");
+ goto out;
+ }
+
+ printf("Detailed partition information\n");
+ end = start + size;
+ printf("Name:\n");
+ printf("%s (ID=%02d)\n\n", ent_name, part_id);
+ printf("%-10s %-10s %-10s\n", "Start", "End", "Actual");
+ printf("0x%08x 0x%08x 0x%08x\n\n", start, end, act);
+
+ printf("Flags:\n");
+
+ l = asprintf(&flags, "%s%s%s%s%s%s%s", has_ecc(ent) ? "ECC [E]\n" : "",
+ has_flag(ent, FFS_MISCFLAGS_PRESERVED) ? "PRESERVED [P]\n" : "",
+ has_flag(ent, FFS_MISCFLAGS_READONLY) ? "READONLY [R]\n" : "",
+ has_flag(ent, FFS_MISCFLAGS_BACKUP) ? "BACKUP [B]\n" : "",
+ has_flag(ent, FFS_MISCFLAGS_REPROVISION) ?
+ "REPROVISION [F]\n" : "",
+ has_flag(ent, FFS_MISCFLAGS_VOLATILE) ? "VOLATILE [V]\n" : "",
+ has_flag(ent, FFS_MISCFLAGS_CLEARECC) ? "CLEARECC [C]\n" : "");
+ ffs_entry_put(ent);
+ if (l < 0) {
+ fprintf(stderr, "Memory allocation failure printing flags!\n");
+ goto out;
+ }
+
+ printf("%s", flags);
+ free(flags);
+
+out:
+ free(ent_name);
+}
+
+static void print_version(void)
+{
+ printf("Open-Power Flash tool %s\n", version);
+}
+
+static void print_help(const char *pname)
+{
+ printf("Usage: %s [options] commands...\n\n", pname);
+ printf(" Options:\n");
+ printf("\t-a address, --address=address\n");
+ printf("\t\tSpecify the start address for erasing, reading\n");
+ printf("\t\tor flashing\n\n");
+ printf("\t-s size, --size=size\n");
+ printf("\t\tSpecify the size in bytes for erasing, reading\n");
+ printf("\t\tor flashing\n\n");
+ printf("\t-P part_name, --partition=part_name\n");
+ printf("\t\tSpecify the partition whose content is to be erased\n");
+ printf("\t\tprogrammed or read. This is an alternative to -a and -s\n");
+ printf("\t\tif both -P and -s are specified, the smallest of the\n");
+ printf("\t\ttwo will be used\n\n");
+ printf("\t-f, --force\n");
+ printf("\t\tDon't ask for confirmation before erasing or flashing\n\n");
+ printf("\t-d, --dummy\n");
+ printf("\t\tDon't write to flash\n\n");
+ printf("\t--direct\n");
+ printf("\t\tBypass all safety provided to you by the kernel driver\n");
+ printf("\t\tand use the flash driver built into pflash.\n");
+ printf("\t\tIf you have mtd devices and you use this command, the\n");
+ printf("\t\tsystem may become unstable.\n");
+ printf("\t\tIf you are reading this sentence then this flag is not\n");
+ printf("\t\twhat you want! Using this feature without knowing\n");
+ printf("\t\twhat it does can and likely will result in a bricked\n");
+ printf("\t\tmachine\n\n");
+ printf("\t-b, --bmc\n");
+ printf("\t\tTarget BMC flash instead of host flash.\n");
+ printf("\t\tNote: This carries a high chance of bricking your BMC if you\n");
+ printf("\t\tdon't know what you're doing. Consider --mtd to be safe(r)\n\n");
+ printf("\t-F filename, --flash-file filename\n");
+ printf("\t\tTarget filename instead of actual flash.\n\n");
+ printf("\t-S, --side\n");
+ printf("\t\tSide of the flash on which to operate, 0 (default) or 1\n\n");
+ printf("\t--skip=N\n");
+ printf("\t\tSkip N number of bytes from the start when reading\n\n");
+ printf("\t-T, --toc\n");
+ printf("\t\tlibffs TOC on which to operate, defaults to 0.\n");
+ printf("\t\tleading 0x is required for interpretation of a hex value\n\n");
+ printf("\t-g\n");
+ printf("\t\tEnable verbose libflash debugging\n\n");
+ printf(" Commands:\n");
+ printf("\t-4, --enable-4B\n");
+ printf("\t\tSwitch the flash and controller to 4-bytes address\n");
+ printf("\t\tmode (no confirmation needed).\n\n");
+ printf("\t-3, --disable-4B\n");
+ printf("\t\tSwitch the flash and controller to 3-bytes address\n");
+ printf("\t\tmode (no confirmation needed).\n\n");
+ printf("\t-r file, --read=file\n");
+ printf("\t\tRead flash content from address into file, use -s\n");
+ printf("\t\tto specify the size to read (or it will use the source\n");
+ printf("\t\tfile size if used in conjunction with -p and -s is not\n");
+ printf("\t\tspecified). When using -r together with -e or -p, the\n");
+ printf("\t\tread will be performed first\n\n");
+ printf("\t-E, --erase-all\n");
+ printf("\t\tErase entire flash chip\n");
+ printf("\t\t(Not supported on all chips/controllers)\n\n");
+ printf("\t-e, --erase\n");
+ printf("\t\tErase the specified region. If size or address are not\n");
+ printf("\t\tspecified, but \'--program\' is used, then the file\n");
+ printf("\t\tsize will be used (rounded to an erase block) and the\n");
+ printf("\t\taddress defaults to 0.\n\n");
+ printf("\t-p file, --program=file\n");
+ printf("\t\tWill program the file to flash. If the address is not\n");
+ printf("\t\tspecified, it will use 0. If the size is not specified\n");
+ printf("\t\tit will use the file size. Otherwise it will limit to\n");
+ printf("\t\tthe specified size (whatever is smaller). If used in\n");
+ printf("\t\tconjunction with any erase command, the erase will\n");
+ printf("\t\ttake place first.\n\n");
+ printf("\t-t, --tune\n");
+ printf("\t\tJust tune the flash controller & access size\n");
+ printf("\t\tMust be used in conjuction with --direct\n");
+ printf("\t\t(Implicit for all other operations)\n\n");
+ printf("\t-c --clear\n");
+ printf("\t\tUsed to ECC clear a partition of the flash\n");
+ printf("\t\tMust be used in conjunction with -P. Will erase the\n");
+ printf("\t\tpartition and then set all the ECC bits as they should be\n\n");
+ printf("\t-9 --ecc\n");
+ printf("\t\tEncode/Decode ECC where specified in the FFS header.\n");
+ printf("\t\tThis 9 byte ECC method is used for some OpenPOWER\n");
+ printf("\t\tpartitions.\n");
+ printf("\t-i, --info\n");
+ printf("\t\tDisplay some information about the flash.\n\n");
+ printf("\t--detail\n");
+ printf("\t\tDisplays detailed info about a particular partition.\n");
+ printf("\t\tAccepts a numeric partition or can be used in conjuction\n");
+ printf("\t\twith the -P flag.\n\n");
+ printf("\t-h, --help\n");
+ printf("\t\tThis message.\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+ const char *pname = argv[0];
+ struct flash_details flash = { 0 };
+ static struct ffs_handle *ffsh = NULL;
+ uint32_t ffs_index;
+ uint32_t address = 0, read_size = 0, detail_id = UINT_MAX;
+ uint32_t write_size = 0, write_size_minus_ecc = 0;
+ bool erase = false, do_clear = false;
+ bool program = false, erase_all = false, info = false, do_read = false;
+ bool enable_4B = false, disable_4B = false;
+ bool show_help = false, show_version = false;
+ bool no_action = false, tune = false;
+ char *write_file = NULL, *read_file = NULL, *part_name = NULL;
+ bool ffs_toc_seen = false, direct = false, print_detail = false;
+ int flash_side = 0, skip_size = 0;
+ int rc = 0;
+
+ while(1) {
+ struct option long_opts[] = {
+ {"address", required_argument, NULL, 'a'},
+ {"size", required_argument, NULL, 's'},
+ {"partition", required_argument, NULL, 'P'},
+ {"bmc", no_argument, NULL, 'b'},
+ {"direct", no_argument, NULL, 'D'},
+ {"enable-4B", no_argument, NULL, '4'},
+ {"disable-4B", no_argument, NULL, '3'},
+ {"read", required_argument, NULL, 'r'},
+ {"erase-all", no_argument, NULL, 'E'},
+ {"erase", no_argument, NULL, 'e'},
+ {"program", required_argument, NULL, 'p'},
+ {"force", no_argument, NULL, 'f'},
+ {"flash-file", required_argument, NULL, 'F'},
+ {"info", no_argument, NULL, 'i'},
+ {"detail", optional_argument, NULL, 'm'},
+ {"tune", no_argument, NULL, 't'},
+ {"dummy", no_argument, NULL, 'd'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {"debug", no_argument, NULL, 'g'},
+ {"side", required_argument, NULL, 'S'},
+ {"skip", required_argument, NULL, 'k'},
+ {"toc", required_argument, NULL, 'T'},
+ {"clear", no_argument, NULL, 'c'},
+ {"ecc", no_argument, NULL, '9'},
+ {NULL, 0, NULL, 0 }
+ };
+ int c, oidx = 0;
+
+ c = getopt_long(argc, argv, "+:a:s:P:r:43Eep:fdihvbtgS:T:c9F:",
+ long_opts, &oidx);
+ if (c == -1)
+ break;
+ switch(c) {
+ char *endptr;
+
+ case 'a':
+ address = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ rc = 1;
+ no_action = true;
+ }
+ break;
+ case 's':
+ read_size = write_size = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ rc = 1;
+ no_action = true;
+ }
+ break;
+ case 'P':
+ free(part_name);
+ part_name = strdup(optarg);
+ break;
+ case '4':
+ enable_4B = true;
+ break;
+ case '3':
+ disable_4B = true;
+ break;
+ case 'r':
+ if (!optarg)
+ break;
+ do_read = true;
+ free(read_file);
+ read_file = strdup(optarg);
+ break;
+ case 'E':
+ erase_all = erase = true;
+ break;
+ case 'e':
+ erase = true;
+ break;
+ case 'D':
+ direct = true;
+ break;
+ case 'p':
+ if (!optarg)
+ break;
+ program = true;
+ free(write_file);
+ write_file = strdup(optarg);
+ break;
+ case 'f':
+ must_confirm = false;
+ break;
+ case 'F':
+ flashfilename = optarg;
+ break;
+ case 'd':
+ must_confirm = false;
+ dummy_run = true;
+ break;
+ case 'i':
+ info = true;
+ break;
+ case 'b':
+ bmc_flash = true;
+ break;
+ case 't':
+ tune = true;
+ break;
+ case 'v':
+ show_version = true;
+ break;
+ case 'h':
+ show_help = show_version = true;
+ break;
+ case 'g':
+ libflash_debug = true;
+ break;
+ case 'S':
+ flash_side = atoi(optarg);
+ break;
+ case 'k':
+ skip_size = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ rc = 1;
+ no_action = true;
+ }
+ break;
+ case 'T':
+ if (!optarg)
+ break;
+ ffs_toc_seen = true;
+ flash.toc = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ rc = 1;
+ no_action = true;
+ }
+ break;
+ case 'c':
+ do_clear = true;
+ break;
+ case 'm':
+ print_detail = true;
+ if (optarg) {
+ detail_id = strtoul(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ rc = 1;
+ no_action = true;
+ }
+ }
+ break;
+ case '9':
+ flash.mark_ecc = true;
+ break;
+ case ':':
+ fprintf(stderr, "Unrecognised option \"%s\" to '%c'\n", optarg, optopt);
+ no_action = true;
+ break;
+ case '?':
+ fprintf(stderr, "Unrecognised option '%c'\n", optopt);
+ no_action = true;
+ break;
+ default:
+ fprintf(stderr , "Encountered unknown error parsing options\n");
+ no_action = true;
+ }
+ }
+
+ if (optind < argc) {
+ /*
+ * It appears not everything passed to pflash was an option, best to
+ * not continue
+ */
+ while (optind < argc)
+ fprintf(stderr, "Unrecognised option or argument \"%s\"\n", argv[optind++]);
+
+ no_action = true;
+ }
+
+ /* Check if we need to access the flash at all (which will
+ * also tune them as a side effect
+ */
+ no_action = no_action || (!erase && !program && !info && !do_read &&
+ !enable_4B && !disable_4B && !tune && !do_clear && !print_detail);
+
+ /* Nothing to do, if we didn't already, print usage */
+ if (no_action && !show_version)
+ show_help = show_version = true;
+
+ if (show_version)
+ print_version();
+ if (show_help)
+ print_help(pname);
+
+ if (no_action)
+ goto out;
+
+ /* --enable-4B and --disable-4B are mutually exclusive */
+ if (enable_4B && disable_4B) {
+ fprintf(stderr, "--enable-4B and --disable-4B are mutually"
+ " exclusive !\n");
+ rc = 1;
+ goto out;
+ }
+
+ /* 4B not supported on BMC flash */
+ if (enable_4B && bmc_flash) {
+ fprintf(stderr, "--enable-4B not supported on BMC flash !\n");
+ rc = 1;
+ goto out;;
+ }
+
+ /* partitions not supported on BMC flash */
+ if (part_name && bmc_flash) {
+ fprintf(stderr, "--partition not supported on BMC flash !\n");
+ rc = 1;
+ goto out;
+ }
+
+ if (print_detail && ((detail_id == UINT_MAX && !part_name)
+ || (detail_id != UINT_MAX && part_name))) {
+ fprintf(stderr, "--detail requires either a partition id or\n");
+ fprintf(stderr, "a partition name with -P\n");
+ }
+
+ /* part-name and erase-all make no sense together */
+ if (part_name && erase_all) {
+ fprintf(stderr, "--partition and --erase-all are mutually"
+ " exclusive !\n");
+ rc = 1;
+ goto out;
+ }
+
+ /* Read command should always come with a file */
+ if (do_read && !read_file) {
+ fprintf(stderr, "Read with no file specified !\n");
+ rc = 1;
+ goto out;
+ }
+
+ /* Skip only supported on read */
+ if (skip_size && !do_read) {
+ fprintf(stderr, "--skip requires a --read command !\n");
+ rc = 1;
+ goto out;
+ }
+
+ /* Program command should always come with a file */
+ if (program && !write_file) {
+ fprintf(stderr, "Program with no file specified !\n");
+ rc = 1;
+ goto out;
+ }
+
+ /* If both partition and address specified, error out */
+ if (address && part_name) {
+ fprintf(stderr, "Specify partition or address, not both !\n");
+ rc = 1;
+ goto out;
+ }
+
+ if (do_clear && !part_name) {
+ fprintf(stderr, "--clear only supported on a partition name\n");
+ rc = 1;
+ goto out;
+ }
+
+ /* Explicitly only support two sides */
+ if (flash_side != 0 && flash_side != 1) {
+ fprintf(stderr, "Unexpected value for --side '%d'\n", flash_side);
+ rc = 1;
+ goto out;
+ }
+
+ if (ffs_toc_seen && flash_side) {
+ fprintf(stderr, "--toc and --side are exclusive");
+ rc = 1;
+ goto out;
+ }
+
+ if (flashfilename && bmc_flash) {
+ fprintf(stderr, "Filename or bmc flash but not both\n");
+ rc = 1;
+ goto out;
+ }
+
+ if (flashfilename && direct) {
+ fprintf(stderr, "Filename or direct access but not both\n");
+ rc = 1;
+ goto out;
+ }
+
+ if (tune && !direct) {
+ fprintf(stderr, "It doesn't make sense to --tune without --direct\n");
+ rc = 1;
+ goto out;
+ }
+
+ if (direct) {
+ /* If -t is passed, then print a nice message */
+ if (tune)
+ printf("Flash and controller tuned\n");
+
+ if (arch_flash_access(NULL, bmc_flash ? BMC_DIRECT : PNOR_DIRECT) == ACCESS_INVAL) {
+ fprintf(stderr, "Can't access %s flash directly on this architecture\n",
+ bmc_flash ? "BMC" : "PNOR");
+ rc = 1;
+ goto out;
+ }
+ } else if (!flashfilename) {
+ if (arch_flash_access(NULL, bmc_flash ? BMC_MTD : PNOR_MTD) == ACCESS_INVAL) {
+ fprintf(stderr, "Can't access %s flash through MTD on this system\n",
+ bmc_flash ? "BMC" : "PNOR");
+ rc = 1;
+ goto out;
+ }
+ }
+
+ if (arch_flash_init(&flash.bl, flashfilename, true)) {
+ fprintf(stderr, "Couldn't initialise architecture flash structures\n");
+ rc = 1;
+ goto out;
+ }
+
+ rc = blocklevel_get_info(flash.bl, &flash.name,
+ &flash.total_size, &flash.erase_granule);
+ if (rc) {
+ fprintf(stderr, "Error %d getting flash info\n", rc);
+ rc = 1;
+ goto close;
+ }
+
+ /* If file specified but not size, get size from file */
+ if (write_file && !write_size) {
+ struct stat stbuf;
+
+ if (stat(write_file, &stbuf)) {
+ perror("Failed to get file size");
+ rc = 1;
+ goto close;
+ }
+ write_size = stbuf.st_size;
+ }
+
+ /* Only take ECC into account under some conditions later */
+ write_size_minus_ecc = write_size;
+
+ /* If read specified and no read_size, use flash size */
+ if (do_read && !read_size && !part_name)
+ read_size = flash.total_size;
+
+ /* We have a partition, adjust read/write size if needed */
+ if (part_name || print_detail) {
+ uint32_t pstart, pmaxsz, pactsize;
+ bool ecc, confirm;
+
+ if (ffs_toc_seen)
+ ffsh = lookup_partition_at_toc(&flash,
+ part_name, &ffs_index);
+ else
+ ffsh = lookup_partition_at_side(&flash, flash_side,
+ part_name, &ffs_index);
+ if (!ffsh)
+ goto close;
+
+ if (!part_name)
+ ffs_index = detail_id;
+
+ rc = ffs_part_info(ffsh, ffs_index, NULL,
+ &pstart, &pmaxsz, &pactsize, &ecc);
+ if (rc) {
+ fprintf(stderr,"Failed to get partition info\n");
+ goto close;
+ }
+
+ if (!ecc && do_clear) {
+ fprintf(stderr, "The partition on which to do --clear "
+ "does not have ECC, are you sure?\n");
+ confirm = check_confirm();
+ if (!confirm) {
+ rc = 1;
+ goto close;
+ }
+ /* Still confirm later on */
+ must_confirm = true;
+ }
+
+ /* Read size is obtained from partition "actual" size */
+ if (!read_size)
+ read_size = pactsize;
+ /* If we're decoding ecc and partition is ECC'd, then adjust */
+ if (ecc && flash.mark_ecc)
+ read_size = ecc_buffer_size_minus_ecc(read_size);
+
+ /* Write size is max size of partition */
+ if (!write_size)
+ write_size = pmaxsz;
+
+ /* But write size can take into account ECC as well */
+ if (ecc && flash.mark_ecc)
+ write_size_minus_ecc = ecc_buffer_size_minus_ecc(write_size);
+ else
+ write_size_minus_ecc = write_size;
+
+ /* Crop write size to partition size if --force was passed */
+ if ((write_size_minus_ecc > pmaxsz) && !must_confirm) {
+ printf("WARNING: Size (%d bytes) larger than partition"
+ " (%d bytes), cropping to fit\n",
+ write_size, pmaxsz);
+ write_size = pmaxsz;
+ } else if (write_size_minus_ecc > pmaxsz) {
+ printf("ERROR: Size (%d bytes) larger than partition"
+ " (%d bytes). Use --force to force\n",
+ write_size, pmaxsz);
+ goto close;
+ }
+
+ /* Set address */
+ address = pstart;
+ } else if (erase) {
+ if ((address | write_size) & (flash.erase_granule - 1)) {
+ if (must_confirm) {
+ printf("ERROR: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
+ address, write_size);
+ printf("Use --force to force\n");
+ goto close;
+ } else {
+ printf("WARNING: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
+ address, write_size);
+ }
+ }
+ }
+
+ /* Process commands */
+
+ /* Both enable and disable can't be set (we've checked) */
+ if (enable_4B)
+ rc = enable_4B_addresses(flash.bl);
+ if (disable_4B)
+ rc = disable_4B_addresses(flash.bl);
+ if (rc)
+ goto close;
+
+ if (info) {
+ /*
+ * Don't pass through modfied TOC value if the modification was done
+ * because of --size, but still respect if it came from --toc (we
+ * assume the user knows what they're doing in that case)
+ */
+ print_flash_info(&flash);
+ }
+
+ if (print_detail)
+ print_partition_detail(ffsh, ffs_index);
+
+ /* Unlock flash (PNOR only) */
+ if ((erase || program || do_clear) && !bmc_flash && !flashfilename) {
+ flash.need_relock = arch_flash_set_wrprotect(flash.bl, false);
+ if (flash.need_relock == -1) {
+ fprintf(stderr, "Architecture doesn't support write protection on flash\n");
+ flash.need_relock = 0;
+ goto close;
+ }
+ }
+ rc = 0;
+ if (do_read)
+ rc = do_read_file(flash.bl, read_file, address, read_size, skip_size);
+ if (!rc && erase_all)
+ rc = erase_chip(&flash);
+ else if (!rc && erase)
+ rc = erase_range(&flash, address, write_size,
+ program, ffsh, ffs_index);
+ if (!rc && program)
+ rc = program_file(flash.bl, write_file, address, write_size_minus_ecc,
+ ffsh, ffs_index);
+ if (!rc && do_clear)
+ rc = set_ecc(&flash, address, write_size);
+
+close:
+ if (flash.need_relock)
+ arch_flash_set_wrprotect(flash.bl, 1);
+ arch_flash_close(flash.bl, flashfilename);
+ if (ffsh)
+ ffs_close(ffsh);
+out:
+ free(part_name);
+ free(read_file);
+ free(write_file);
+
+ return rc;
+}
diff --git a/roms/skiboot/external/pflash/progress.c b/roms/skiboot/external/pflash/progress.c
new file mode 100644
index 000000000..b98838473
--- /dev/null
+++ b/roms/skiboot/external/pflash/progress.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * The most important part of pflash, the progress bars
+ *
+ * Copyright 2014-2017 IBM Corp.
+ */
+
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "progress.h"
+
+static uint64_t progress_max;
+static uint64_t progress_pcent;
+static uint64_t progress_n_upd;
+static time_t progress_prevsec;
+static struct timespec progress_start;
+
+#define PROGRESS_CHARS 50
+
+void progress_init(uint64_t count)
+{
+ unsigned int i;
+
+ progress_max = count;
+ progress_pcent = 0;
+ progress_n_upd = ULONG_MAX;
+ progress_prevsec = ULONG_MAX;
+
+ printf("\r[");
+ for (i = 0; i < PROGRESS_CHARS; i++)
+ printf(" ");
+ printf("] 0%%");
+ fflush(stdout);
+ clock_gettime(CLOCK_MONOTONIC, &progress_start);}
+
+void progress_tick(uint64_t cur)
+{
+ unsigned int i, pos;
+ struct timespec now;
+ uint64_t pcent;
+ double sec;
+
+ pcent = (cur * 100) / progress_max;
+ if (progress_pcent == pcent && cur < progress_n_upd &&
+ cur < progress_max)
+ return;
+ progress_pcent = pcent;
+ pos = (pcent * PROGRESS_CHARS) / 101;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ printf("\r[");
+ for (i = 0; i <= pos; i++)
+ printf("=");
+ for (; i < PROGRESS_CHARS; i++)
+ printf(" ");
+ printf("] %" PRIu64 "%%", pcent);
+
+ sec = difftime(now.tv_sec, progress_start.tv_sec);
+ if (sec >= 5 && pcent > 0) {
+ uint64_t persec = cur / sec;
+ uint64_t rem_sec;
+
+ if (!persec)
+ persec = 1;
+ progress_n_upd = cur + persec;
+ rem_sec = ((sec * 100) + (pcent / 2)) / pcent - sec;
+ if (rem_sec > progress_prevsec)
+ rem_sec = progress_prevsec;
+ progress_prevsec = rem_sec;
+ if (rem_sec < 60)
+ printf(" ETA:%" PRIu64 "s ", rem_sec);
+ else {
+ printf(" ETA:%" PRIu64 ":%02" PRIu64 ":%02" PRIu64 " ",
+ rem_sec / 3600,
+ (rem_sec / 60) % 60,
+ rem_sec % 60);
+ }
+ }
+
+ fflush(stdout);
+}
+
+void progress_end(void)
+{
+ printf("\n");
+}
diff --git a/roms/skiboot/external/pflash/progress.h b/roms/skiboot/external/pflash/progress.h
new file mode 100644
index 000000000..eb390d542
--- /dev/null
+++ b/roms/skiboot/external/pflash/progress.h
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * Copyright 2014-2017 IBM Corp.
+ */
+
+#ifndef __PROGRESS_H
+#define __PROGRESS_H
+
+#include <inttypes.h>
+
+void progress_init(uint64_t count);
+void progress_tick(uint64_t cur);
+void progress_end(void);
+
+#endif /* __PROGRESS_H */
diff --git a/roms/skiboot/external/pflash/rules.mk b/roms/skiboot/external/pflash/rules.mk
new file mode 100644
index 000000000..1d1b60486
--- /dev/null
+++ b/roms/skiboot/external/pflash/rules.mk
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+.DEFAULT_GOAL := all
+
+override CFLAGS += -O2 -Wall -I.
+LIBFLASH_FILES := libflash.c libffs.c ecc.c blocklevel.c file.c
+LIBFLASH_OBJS := $(addprefix libflash-, $(LIBFLASH_FILES:.c=.o))
+LIBFLASH_SRC := $(addprefix libflash/,$(LIBFLASH_FILES))
+CCAN_FILES := list.c
+CCAN_OBJS := $(addprefix ccan-list-, $(CCAN_FILES:.c=.o))
+CCAN_SRC := $(addprefix ccan/list/,$(CCAN_FILES))
+PFLASH_OBJS := pflash.o progress.o version.o common-arch_flash.o
+OBJS := $(PFLASH_OBJS) $(LIBFLASH_OBJS) $(CCAN_OBJS)
+EXE := pflash
+sbindir = $(prefix)/sbin
+datadir = $(prefix)/share
+mandir = $(datadir)/man
+
+PFLASH_VERSION ?= $(shell ../../make_version.sh $(EXE))
+LINKAGE ?= static
+
+ifeq ($(LINKAGE),dynamic)
+include ../shared/rules.mk
+SHARED := ../shared/$(SHARED_NAME)
+OBJS := $(PFLASH_OBJS) $(SHARED)
+INSTALLDEPS += install-shared
+
+install-shared:
+ $(MAKE) -C ../shared install prefix=$(prefix)
+
+$(SHARED):
+ $(MAKE) -C ../shared
+endif
+
+version.c: .version
+ @(if [ "a$(PFLASH_VERSION)" = "a" ]; then \
+ echo "#error You need to set PFLASH_VERSION environment variable" > $@ ;\
+ else \
+ echo "const char version[] = \"$(PFLASH_VERSION)\";" ;\
+ fi) > $@
+
+%.o : %.c | links
+ $(Q_CC)$(CC) $(CFLAGS) -c $< -o $@
+
+$(LIBFLASH_SRC): | links
+
+$(CCAN_SRC): | links
+
+$(LIBFLASH_OBJS): libflash-%.o : libflash/%.c | links
+ $(Q_CC)$(CC) $(CFLAGS) -c $< -o $@
+
+$(CCAN_OBJS): ccan-list-%.o: ccan/list/%.c | links
+ $(Q_CC)$(CC) $(CFLAGS) -c $< -o $@
+
+$(EXE): $(OBJS)
+ $(Q_CC)$(CC) $(LDFLAGS) $(CFLAGS) $^ -lrt -o $@
+
diff --git a/roms/skiboot/external/pflash/test/files/01-info.ffs b/roms/skiboot/external/pflash/test/files/01-info.ffs
new file mode 100644
index 000000000..41cbb68cb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/files/01-info.ffs
@@ -0,0 +1,6 @@
+ONE,0x00003000,0x00001000,EV,,/dev/zero
+TWO,0x00004000,0x00001000,EF,,/dev/zero
+THREE,0x00005000,0x00001000,EF,,/dev/zero
+FOUR,0x00006000,0x00001000,EF,,/dev/zero
+FIVE,0x00007000,0x1000,L,,/dev/zero
+SIX,0x00008000,0x1000,C,,/dev/zero
diff --git a/roms/skiboot/external/pflash/test/files/02-erase.ffs b/roms/skiboot/external/pflash/test/files/02-erase.ffs
new file mode 100644
index 000000000..ff64d4e69
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/files/02-erase.ffs
@@ -0,0 +1,4 @@
+ONE,0x00000300,0x00000100,EV,,/dev/urandom
+TWO,0x00000400,0x00000100,EF,,/dev/urandom
+THREE,0x00000500,0x00000100,EF,,/dev/urandom
+FOUR,0x00000600,0x00000100,EF,,/dev/urandom
diff --git a/roms/skiboot/external/pflash/test/files/03-erase-parts.ffs b/roms/skiboot/external/pflash/test/files/03-erase-parts.ffs
new file mode 100644
index 000000000..ff64d4e69
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/files/03-erase-parts.ffs
@@ -0,0 +1,4 @@
+ONE,0x00000300,0x00000100,EV,,/dev/urandom
+TWO,0x00000400,0x00000100,EF,,/dev/urandom
+THREE,0x00000500,0x00000100,EF,,/dev/urandom
+FOUR,0x00000600,0x00000100,EF,,/dev/urandom
diff --git a/roms/skiboot/external/pflash/test/files/04-program-rand.ffs b/roms/skiboot/external/pflash/test/files/04-program-rand.ffs
new file mode 100644
index 000000000..ff64d4e69
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/files/04-program-rand.ffs
@@ -0,0 +1,4 @@
+ONE,0x00000300,0x00000100,EV,,/dev/urandom
+TWO,0x00000400,0x00000100,EF,,/dev/urandom
+THREE,0x00000500,0x00000100,EF,,/dev/urandom
+FOUR,0x00000600,0x00000100,EF,,/dev/urandom
diff --git a/roms/skiboot/external/pflash/test/files/05-bad-numbers.ffs b/roms/skiboot/external/pflash/test/files/05-bad-numbers.ffs
new file mode 100644
index 000000000..ff64d4e69
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/files/05-bad-numbers.ffs
@@ -0,0 +1,4 @@
+ONE,0x00000300,0x00000100,EV,,/dev/urandom
+TWO,0x00000400,0x00000100,EF,,/dev/urandom
+THREE,0x00000500,0x00000100,EF,,/dev/urandom
+FOUR,0x00000600,0x00000100,EF,,/dev/urandom
diff --git a/roms/skiboot/external/pflash/test/files/06-miscprint.ffs b/roms/skiboot/external/pflash/test/files/06-miscprint.ffs
new file mode 100644
index 000000000..d7e91b0e1
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/files/06-miscprint.ffs
@@ -0,0 +1,6 @@
+PRESERVED,0x003000,0x1000,P,,/dev/zero
+READONLY,0x0004000,0x1000,R,,/dev/zero
+REPROVISION,0x5000,0x1000,F,,/dev/zero
+BACKUP,0x000006000,0x1000,B,,/dev/zero
+VOLATILE,0x000007000,0x1000,V,,/dev/zero
+CLEARECC,0x000008000,0x1000,C,,/dev/zero
diff --git a/roms/skiboot/external/pflash/test/make-check-test b/roms/skiboot/external/pflash/test/make-check-test
new file mode 100755
index 000000000..7f0094860
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/make-check-test
@@ -0,0 +1 @@
+make -C external/pflash/ check
diff --git a/roms/skiboot/external/pflash/test/results/00-usage.err b/roms/skiboot/external/pflash/test/results/00-usage.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/00-usage.err
diff --git a/roms/skiboot/external/pflash/test/results/00-usage.out b/roms/skiboot/external/pflash/test/results/00-usage.out
new file mode 100644
index 000000000..a3721ca8e
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/00-usage.out
@@ -0,0 +1,114 @@
+Open-Power Flash tool VERSION
+Usage: ./pflash [options] commands...
+
+ Options:
+ -a address, --address=address
+ Specify the start address for erasing, reading
+ or flashing
+
+ -s size, --size=size
+ Specify the size in bytes for erasing, reading
+ or flashing
+
+ -P part_name, --partition=part_name
+ Specify the partition whose content is to be erased
+ programmed or read. This is an alternative to -a and -s
+ if both -P and -s are specified, the smallest of the
+ two will be used
+
+ -f, --force
+ Don't ask for confirmation before erasing or flashing
+
+ -d, --dummy
+ Don't write to flash
+
+ --direct
+ Bypass all safety provided to you by the kernel driver
+ and use the flash driver built into pflash.
+ If you have mtd devices and you use this command, the
+ system may become unstable.
+ If you are reading this sentence then this flag is not
+ what you want! Using this feature without knowing
+ what it does can and likely will result in a bricked
+ machine
+
+ -b, --bmc
+ Target BMC flash instead of host flash.
+ Note: This carries a high chance of bricking your BMC if you
+ don't know what you're doing. Consider --mtd to be safe(r)
+
+ -F filename, --flash-file filename
+ Target filename instead of actual flash.
+
+ -S, --side
+ Side of the flash on which to operate, 0 (default) or 1
+
+ --skip=N
+ Skip N number of bytes from the start when reading
+
+ -T, --toc
+ libffs TOC on which to operate, defaults to 0.
+ leading 0x is required for interpretation of a hex value
+
+ -g
+ Enable verbose libflash debugging
+
+ Commands:
+ -4, --enable-4B
+ Switch the flash and controller to 4-bytes address
+ mode (no confirmation needed).
+
+ -3, --disable-4B
+ Switch the flash and controller to 3-bytes address
+ mode (no confirmation needed).
+
+ -r file, --read=file
+ Read flash content from address into file, use -s
+ to specify the size to read (or it will use the source
+ file size if used in conjunction with -p and -s is not
+ specified). When using -r together with -e or -p, the
+ read will be performed first
+
+ -E, --erase-all
+ Erase entire flash chip
+ (Not supported on all chips/controllers)
+
+ -e, --erase
+ Erase the specified region. If size or address are not
+ specified, but '--program' is used, then the file
+ size will be used (rounded to an erase block) and the
+ address defaults to 0.
+
+ -p file, --program=file
+ Will program the file to flash. If the address is not
+ specified, it will use 0. If the size is not specified
+ it will use the file size. Otherwise it will limit to
+ the specified size (whatever is smaller). If used in
+ conjunction with any erase command, the erase will
+ take place first.
+
+ -t, --tune
+ Just tune the flash controller & access size
+ Must be used in conjuction with --direct
+ (Implicit for all other operations)
+
+ -c --clear
+ Used to ECC clear a partition of the flash
+ Must be used in conjunction with -P. Will erase the
+ partition and then set all the ECC bits as they should be
+
+ -9 --ecc
+ Encode/Decode ECC where specified in the FFS header.
+ This 9 byte ECC method is used for some OpenPOWER
+ partitions.
+ -i, --info
+ Display some information about the flash.
+
+ --detail
+ Displays detailed info about a particular partition.
+ Accepts a numeric partition or can be used in conjuction
+ with the -P flag.
+
+ -h, --help
+ This message.
+
diff --git a/roms/skiboot/external/pflash/test/results/01-info.err b/roms/skiboot/external/pflash/test/results/01-info.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/01-info.err
diff --git a/roms/skiboot/external/pflash/test/results/01-info.out b/roms/skiboot/external/pflash/test/results/01-info.out
new file mode 100644
index 000000000..6dfa9216f
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/01-info.out
@@ -0,0 +1,15 @@
+Flash info:
+-----------
+Name = FILE
+Total size = 0MB Flags E:ECC, P:PRESERVED, R:READONLY, B:BACKUP
+Erase granule = 0KB F:REPROVISION, V:VOLATILE, C:CLEARECC
+
+TOC@0x00000000 Partitions:
+-----------
+ID=00 part 0x00000000..0x00001000 (actual=0x00001000) [----------]
+ID=01 ONE 0x00003000..0x00004000 (actual=0x00001000) [E--------V]
+ID=02 TWO 0x00004000..0x00005000 (actual=0x00001000) [E-----F---]
+ID=03 THREE 0x00005000..0x00006000 (actual=0x00001000) [E-----F---]
+ID=04 FOUR 0x00006000..0x00007000 (actual=0x00001000) [E-----F---]
+ID=05 FIVE 0x00007000..0x00008000 (actual=0x00001000) [-L--------]
+ID=06 SIX 0x00008000..0x00009000 (actual=0x00001000) [--------C-]
diff --git a/roms/skiboot/external/pflash/test/results/02-erase.err b/roms/skiboot/external/pflash/test/results/02-erase.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/02-erase.err
diff --git a/roms/skiboot/external/pflash/test/results/02-erase.out b/roms/skiboot/external/pflash/test/results/02-erase.out
new file mode 100644
index 000000000..7d251a70c
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/02-erase.out
@@ -0,0 +1,105 @@
+About to erase chip !
+WARNING ! This will modify your HOST flash chip content !
+Enter "yes" to confirm:Erasing... (may take a while)
+
+[ ] 0%
+[= ] 1%
+[= ] 2%
+[== ] 3%
+[== ] 4%
+[=== ] 5%
+[=== ] 6%
+[==== ] 7%
+[==== ] 8%
+[===== ] 9%
+[===== ] 10%
+[====== ] 11%
+[====== ] 12%
+[======= ] 13%
+[======= ] 14%
+[======== ] 15%
+[======== ] 16%
+[========= ] 17%
+[========= ] 18%
+[========== ] 19%
+[========== ] 20%
+[=========== ] 21%
+[=========== ] 22%
+[============ ] 23%
+[============ ] 24%
+[============= ] 25%
+[============= ] 26%
+[============== ] 27%
+[============== ] 28%
+[=============== ] 29%
+[=============== ] 30%
+[================ ] 31%
+[================ ] 32%
+[================= ] 33%
+[================= ] 34%
+[================== ] 35%
+[================== ] 36%
+[=================== ] 37%
+[=================== ] 38%
+[==================== ] 39%
+[==================== ] 40%
+[===================== ] 41%
+[===================== ] 42%
+[====================== ] 43%
+[====================== ] 44%
+[======================= ] 45%
+[======================= ] 46%
+[======================== ] 47%
+[======================== ] 48%
+[========================= ] 49%
+[========================= ] 50%
+[========================== ] 51%
+[========================== ] 52%
+[=========================== ] 53%
+[=========================== ] 54%
+[============================ ] 55%
+[============================ ] 56%
+[============================= ] 57%
+[============================= ] 58%
+[============================== ] 59%
+[============================== ] 60%
+[=============================== ] 61%
+[=============================== ] 62%
+[================================ ] 63%
+[================================ ] 64%
+[================================= ] 65%
+[================================= ] 66%
+[================================== ] 67%
+[================================== ] 68%
+[=================================== ] 69%
+[=================================== ] 70%
+[==================================== ] 71%
+[==================================== ] 72%
+[===================================== ] 73%
+[===================================== ] 74%
+[====================================== ] 75%
+[====================================== ] 76%
+[======================================= ] 77%
+[======================================= ] 78%
+[======================================== ] 79%
+[======================================== ] 80%
+[========================================= ] 81%
+[========================================= ] 82%
+[========================================== ] 83%
+[========================================== ] 84%
+[=========================================== ] 85%
+[=========================================== ] 86%
+[============================================ ] 87%
+[============================================ ] 88%
+[============================================= ] 89%
+[============================================= ] 90%
+[============================================== ] 91%
+[============================================== ] 92%
+[=============================================== ] 93%
+[=============================================== ] 94%
+[================================================ ] 95%
+[================================================ ] 96%
+[================================================= ] 97%
+[================================================= ] 98%
+[==================================================] 99%
+done !
diff --git a/roms/skiboot/external/pflash/test/results/03-erase-parts.err b/roms/skiboot/external/pflash/test/results/03-erase-parts.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/03-erase-parts.err
diff --git a/roms/skiboot/external/pflash/test/results/03-erase-parts.out b/roms/skiboot/external/pflash/test/results/03-erase-parts.out
new file mode 100644
index 000000000..28f0b23d1
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/03-erase-parts.out
@@ -0,0 +1,106 @@
+About to erase 0x00000300..0x00000400 !
+WARNING ! This will modify your HOST flash chip content !
+Enter "yes" to confirm:Erasing...
+
+[ ] 0%
+[= ] 1%
+[= ] 2%
+[== ] 3%
+[== ] 4%
+[=== ] 5%
+[=== ] 6%
+[==== ] 7%
+[==== ] 8%
+[===== ] 9%
+[===== ] 10%
+[====== ] 11%
+[====== ] 12%
+[======= ] 13%
+[======= ] 14%
+[======== ] 15%
+[======== ] 16%
+[========= ] 17%
+[========= ] 18%
+[========== ] 19%
+[========== ] 20%
+[=========== ] 21%
+[=========== ] 22%
+[============ ] 23%
+[============ ] 24%
+[============= ] 25%
+[============= ] 26%
+[============== ] 27%
+[============== ] 28%
+[=============== ] 29%
+[=============== ] 30%
+[================ ] 31%
+[================ ] 32%
+[================= ] 33%
+[================= ] 34%
+[================== ] 35%
+[================== ] 36%
+[=================== ] 37%
+[=================== ] 38%
+[==================== ] 39%
+[==================== ] 40%
+[===================== ] 41%
+[===================== ] 42%
+[====================== ] 43%
+[====================== ] 44%
+[======================= ] 45%
+[======================= ] 46%
+[======================== ] 47%
+[======================== ] 48%
+[========================= ] 49%
+[========================= ] 50%
+[========================== ] 51%
+[========================== ] 52%
+[=========================== ] 53%
+[=========================== ] 54%
+[============================ ] 55%
+[============================ ] 56%
+[============================= ] 57%
+[============================= ] 58%
+[============================== ] 59%
+[============================== ] 60%
+[=============================== ] 61%
+[=============================== ] 62%
+[================================ ] 63%
+[================================ ] 64%
+[================================= ] 65%
+[================================= ] 66%
+[================================== ] 67%
+[================================== ] 68%
+[=================================== ] 69%
+[=================================== ] 70%
+[==================================== ] 71%
+[==================================== ] 72%
+[===================================== ] 73%
+[===================================== ] 74%
+[====================================== ] 75%
+[====================================== ] 76%
+[======================================= ] 77%
+[======================================= ] 78%
+[======================================== ] 79%
+[======================================== ] 80%
+[========================================= ] 81%
+[========================================= ] 82%
+[========================================== ] 83%
+[========================================== ] 84%
+[=========================================== ] 85%
+[=========================================== ] 86%
+[============================================ ] 87%
+[============================================ ] 88%
+[============================================= ] 89%
+[============================================= ] 90%
+[============================================== ] 91%
+[============================================== ] 92%
+[=============================================== ] 93%
+[=============================================== ] 94%
+[================================================ ] 95%
+[================================================ ] 96%
+[================================================= ] 97%
+[================================================= ] 98%
+[==================================================] 99%
+[==================================================] 100%
+Updating actual size in partition header...
diff --git a/roms/skiboot/external/pflash/test/results/04-program-rand.err b/roms/skiboot/external/pflash/test/results/04-program-rand.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/04-program-rand.err
diff --git a/roms/skiboot/external/pflash/test/results/04-program-rand.out b/roms/skiboot/external/pflash/test/results/04-program-rand.out
new file mode 100644
index 000000000..b0df327cd
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/04-program-rand.out
@@ -0,0 +1,111 @@
+About to erase 0x00000300..0x00000400 !
+WARNING ! This will modify your HOST flash chip content !
+Enter "yes" to confirm:Erasing...
+
+[ ] 0%
+[= ] 1%
+[= ] 2%
+[== ] 3%
+[== ] 4%
+[=== ] 5%
+[=== ] 6%
+[==== ] 7%
+[==== ] 8%
+[===== ] 9%
+[===== ] 10%
+[====== ] 11%
+[====== ] 12%
+[======= ] 13%
+[======= ] 14%
+[======== ] 15%
+[======== ] 16%
+[========= ] 17%
+[========= ] 18%
+[========== ] 19%
+[========== ] 20%
+[=========== ] 21%
+[=========== ] 22%
+[============ ] 23%
+[============ ] 24%
+[============= ] 25%
+[============= ] 26%
+[============== ] 27%
+[============== ] 28%
+[=============== ] 29%
+[=============== ] 30%
+[================ ] 31%
+[================ ] 32%
+[================= ] 33%
+[================= ] 34%
+[================== ] 35%
+[================== ] 36%
+[=================== ] 37%
+[=================== ] 38%
+[==================== ] 39%
+[==================== ] 40%
+[===================== ] 41%
+[===================== ] 42%
+[====================== ] 43%
+[====================== ] 44%
+[======================= ] 45%
+[======================= ] 46%
+[======================== ] 47%
+[======================== ] 48%
+[========================= ] 49%
+[========================= ] 50%
+[========================== ] 51%
+[========================== ] 52%
+[=========================== ] 53%
+[=========================== ] 54%
+[============================ ] 55%
+[============================ ] 56%
+[============================= ] 57%
+[============================= ] 58%
+[============================== ] 59%
+[============================== ] 60%
+[=============================== ] 61%
+[=============================== ] 62%
+[================================ ] 63%
+[================================ ] 64%
+[================================= ] 65%
+[================================= ] 66%
+[================================== ] 67%
+[================================== ] 68%
+[=================================== ] 69%
+[=================================== ] 70%
+[==================================== ] 71%
+[==================================== ] 72%
+[===================================== ] 73%
+[===================================== ] 74%
+[====================================== ] 75%
+[====================================== ] 76%
+[======================================= ] 77%
+[======================================= ] 78%
+[======================================== ] 79%
+[======================================== ] 80%
+[========================================= ] 81%
+[========================================= ] 82%
+[========================================== ] 83%
+[========================================== ] 84%
+[=========================================== ] 85%
+[=========================================== ] 86%
+[============================================ ] 87%
+[============================================ ] 88%
+[============================================= ] 89%
+[============================================= ] 90%
+[============================================== ] 91%
+[============================================== ] 92%
+[=============================================== ] 93%
+[=============================================== ] 94%
+[================================================ ] 95%
+[================================================ ] 96%
+[================================================= ] 97%
+[================================================= ] 98%
+[==================================================] 99%
+[==================================================] 100%
+About to program "FILE" at 0x00000300..0x00000400 !
+Programming & Verifying...
+
+[ ] 0%
+[==================================================] 100%
+Updating actual size in partition header...
diff --git a/roms/skiboot/external/pflash/test/results/05-bad-numbers.err b/roms/skiboot/external/pflash/test/results/05-bad-numbers.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/05-bad-numbers.err
diff --git a/roms/skiboot/external/pflash/test/results/05-bad-numbers.out b/roms/skiboot/external/pflash/test/results/05-bad-numbers.out
new file mode 100644
index 000000000..2a76c28c0
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/05-bad-numbers.out
@@ -0,0 +1,224 @@
+Open-Power Flash tool VERSION
+Usage: ./pflash [options] commands...
+
+ Options:
+ -a address, --address=address
+ Specify the start address for erasing, reading
+ or flashing
+
+ -s size, --size=size
+ Specify the size in bytes for erasing, reading
+ or flashing
+
+ -P part_name, --partition=part_name
+ Specify the partition whose content is to be erased
+ programmed or read. This is an alternative to -a and -s
+ if both -P and -s are specified, the smallest of the
+ two will be used
+
+ -f, --force
+ Don't ask for confirmation before erasing or flashing
+
+ -d, --dummy
+ Don't write to flash
+
+ --direct
+ Bypass all safety provided to you by the kernel driver
+ and use the flash driver built into pflash.
+ If you have mtd devices and you use this command, the
+ system may become unstable.
+ If you are reading this sentence then this flag is not
+ what you want! Using this feature without knowing
+ what it does can and likely will result in a bricked
+ machine
+
+ -b, --bmc
+ Target BMC flash instead of host flash.
+ Note: This carries a high chance of bricking your BMC if you
+ don't know what you're doing. Consider --mtd to be safe(r)
+
+ -F filename, --flash-file filename
+ Target filename instead of actual flash.
+
+ -S, --side
+ Side of the flash on which to operate, 0 (default) or 1
+
+ --skip=N
+ Skip N number of bytes from the start when reading
+
+ -T, --toc
+ libffs TOC on which to operate, defaults to 0.
+ leading 0x is required for interpretation of a hex value
+
+ -g
+ Enable verbose libflash debugging
+
+ Commands:
+ -4, --enable-4B
+ Switch the flash and controller to 4-bytes address
+ mode (no confirmation needed).
+
+ -3, --disable-4B
+ Switch the flash and controller to 3-bytes address
+ mode (no confirmation needed).
+
+ -r file, --read=file
+ Read flash content from address into file, use -s
+ to specify the size to read (or it will use the source
+ file size if used in conjunction with -p and -s is not
+ specified). When using -r together with -e or -p, the
+ read will be performed first
+
+ -E, --erase-all
+ Erase entire flash chip
+ (Not supported on all chips/controllers)
+
+ -e, --erase
+ Erase the specified region. If size or address are not
+ specified, but '--program' is used, then the file
+ size will be used (rounded to an erase block) and the
+ address defaults to 0.
+
+ -p file, --program=file
+ Will program the file to flash. If the address is not
+ specified, it will use 0. If the size is not specified
+ it will use the file size. Otherwise it will limit to
+ the specified size (whatever is smaller). If used in
+ conjunction with any erase command, the erase will
+ take place first.
+
+ -t, --tune
+ Just tune the flash controller & access size
+ Must be used in conjuction with --direct
+ (Implicit for all other operations)
+
+ -c --clear
+ Used to ECC clear a partition of the flash
+ Must be used in conjunction with -P. Will erase the
+ partition and then set all the ECC bits as they should be
+
+ -9 --ecc
+ Encode/Decode ECC where specified in the FFS header.
+ This 9 byte ECC method is used for some OpenPOWER
+ partitions.
+ -i, --info
+ Display some information about the flash.
+
+ --detail
+ Displays detailed info about a particular partition.
+ Accepts a numeric partition or can be used in conjuction
+ with the -P flag.
+
+ -h, --help
+ This message.
+
+About to erase 0x00000300..0x00000400 !
+WARNING ! This will modify your HOST flash chip content !
+Enter "yes" to confirm:Erasing...
+
+[ ] 0%
+[= ] 1%
+[= ] 2%
+[== ] 3%
+[== ] 4%
+[=== ] 5%
+[=== ] 6%
+[==== ] 7%
+[==== ] 8%
+[===== ] 9%
+[===== ] 10%
+[====== ] 11%
+[====== ] 12%
+[======= ] 13%
+[======= ] 14%
+[======== ] 15%
+[======== ] 16%
+[========= ] 17%
+[========= ] 18%
+[========== ] 19%
+[========== ] 20%
+[=========== ] 21%
+[=========== ] 22%
+[============ ] 23%
+[============ ] 24%
+[============= ] 25%
+[============= ] 26%
+[============== ] 27%
+[============== ] 28%
+[=============== ] 29%
+[=============== ] 30%
+[================ ] 31%
+[================ ] 32%
+[================= ] 33%
+[================= ] 34%
+[================== ] 35%
+[================== ] 36%
+[=================== ] 37%
+[=================== ] 38%
+[==================== ] 39%
+[==================== ] 40%
+[===================== ] 41%
+[===================== ] 42%
+[====================== ] 43%
+[====================== ] 44%
+[======================= ] 45%
+[======================= ] 46%
+[======================== ] 47%
+[======================== ] 48%
+[========================= ] 49%
+[========================= ] 50%
+[========================== ] 51%
+[========================== ] 52%
+[=========================== ] 53%
+[=========================== ] 54%
+[============================ ] 55%
+[============================ ] 56%
+[============================= ] 57%
+[============================= ] 58%
+[============================== ] 59%
+[============================== ] 60%
+[=============================== ] 61%
+[=============================== ] 62%
+[================================ ] 63%
+[================================ ] 64%
+[================================= ] 65%
+[================================= ] 66%
+[================================== ] 67%
+[================================== ] 68%
+[=================================== ] 69%
+[=================================== ] 70%
+[==================================== ] 71%
+[==================================== ] 72%
+[===================================== ] 73%
+[===================================== ] 74%
+[====================================== ] 75%
+[====================================== ] 76%
+[======================================= ] 77%
+[======================================= ] 78%
+[======================================== ] 79%
+[======================================== ] 80%
+[========================================= ] 81%
+[========================================= ] 82%
+[========================================== ] 83%
+[========================================== ] 84%
+[=========================================== ] 85%
+[=========================================== ] 86%
+[============================================ ] 87%
+[============================================ ] 88%
+[============================================= ] 89%
+[============================================= ] 90%
+[============================================== ] 91%
+[============================================== ] 92%
+[=============================================== ] 93%
+[=============================================== ] 94%
+[================================================ ] 95%
+[================================================ ] 96%
+[================================================= ] 97%
+[================================================= ] 98%
+[==================================================] 99%
+[==================================================] 100%
+About to program "FILE" at 0x00000300..0x00000400 !
+Programming & Verifying...
+
+[ ] 0%
+[==================================================] 100%
diff --git a/roms/skiboot/external/pflash/test/results/06-miscprint.err b/roms/skiboot/external/pflash/test/results/06-miscprint.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/06-miscprint.err
diff --git a/roms/skiboot/external/pflash/test/results/06-miscprint.out b/roms/skiboot/external/pflash/test/results/06-miscprint.out
new file mode 100644
index 000000000..58a6b889c
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/results/06-miscprint.out
@@ -0,0 +1,54 @@
+Detailed partition information
+Name:
+PRESERVED (ID=01)
+
+Start End Actual
+0x00003000 0x00004000 0x00001000
+
+Flags:
+PRESERVED [P]
+Detailed partition information
+Name:
+READONLY (ID=02)
+
+Start End Actual
+0x00004000 0x00005000 0x00001000
+
+Flags:
+READONLY [R]
+Detailed partition information
+Name:
+REPROVISION (ID=03)
+
+Start End Actual
+0x00005000 0x00006000 0x00001000
+
+Flags:
+REPROVISION [F]
+Detailed partition information
+Name:
+BACKUP (ID=04)
+
+Start End Actual
+0x00006000 0x00007000 0x00000000
+
+Flags:
+BACKUP [B]
+Detailed partition information
+Name:
+VOLATILE (ID=05)
+
+Start End Actual
+0x00007000 0x00008000 0x00001000
+
+Flags:
+VOLATILE [V]
+Detailed partition information
+Name:
+CLEARECC (ID=06)
+
+Start End Actual
+0x00008000 0x00009000 0x00001000
+
+Flags:
+CLEARECC [C]
diff --git a/roms/skiboot/external/pflash/test/test-pflash b/roms/skiboot/external/pflash/test/test-pflash
new file mode 100755
index 000000000..dd775bda3
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/test-pflash
@@ -0,0 +1,59 @@
+#! /bin/sh
+
+. test/test.sh
+
+get_part_start() {
+ #We want to fail the test if the caller passed garbage
+ if [ "$#" -ne 2 ] || ! grep -q "$2" "$1" ; then
+ fail_test;
+ fi
+ grep "$2" "$1" | cut -f2 -d, | xargs printf "%d";
+}
+
+get_part_len() {
+ #We want to fail the test if the caller passed garbage
+ if [ "$#" -ne 2 ] || ! grep -q "$2" "$1" ; then
+ fail_test;
+ fi
+ grep "$2" "$1" | cut -f3 -d, | xargs printf "%d";
+}
+
+get_part_end() {
+ start=$(get_part_start "$1" "$2");
+ len=$(get_part_len "$1" "$2");
+ expr "$start" \+ "$len";
+}
+
+cmp_with_ff() {
+ if [ "$#" -ne 3 ] ; then
+ fail_test;
+ fi
+ file="$1";
+ start="$2";
+ len="$3";
+
+ blank=$(mktemp --tmpdir="$DATA_DIR" blank.pnorXXXXXX);
+ dd status=none if=/dev/zero bs="$len" count=1 | tr '\000' '\377' > "$blank"
+ cmp --bytes="$len" --ignore-initial="$start:0" "$file" "$blank";
+ if [ "$?" -ne 0 ] ; then
+ fail_test;
+ fi
+ #fail_test; will trigger a cleanup straight away
+ rm $blank;
+}
+
+#The reason for it is that this way there is a completely independant
+#way of calculating checksums so if checksums fail, we can be
+#confident its because libflash/libffs changed
+update_checksum() {
+ if [ "$#" -ne 2 ] ; then
+ fail_test;
+ fi
+ file=$1;
+ part=$2;
+ dd if="$file" bs=1 skip="$part" count=124 status=none | perl -e 'use integer; binmode STDIN; binmode STDOUT; my $result=0; while (read STDIN, $word, 4) { $result = $result ^ unpack("N", $word); } print pack("N",$result)' | dd of="$file" seek="$(expr $part \+ 124)" bs=1 count=4 status=none conv=notrunc
+}
+
+run_tests "test/tests/*" "test/results" "test/files"
+
+
diff --git a/roms/skiboot/external/pflash/test/tests/00-usage b/roms/skiboot/external/pflash/test/tests/00-usage
new file mode 100644
index 000000000..4c4ba2aa5
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/tests/00-usage
@@ -0,0 +1,13 @@
+#! /bin/sh
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+run_binary "./pflash" "-h"
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+strip_version_from_result "pflash"
+
+diff_with_result
+
+pass_test
diff --git a/roms/skiboot/external/pflash/test/tests/01-info b/roms/skiboot/external/pflash/test/tests/01-info
new file mode 100644
index 000000000..583d275c4
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/tests/01-info
@@ -0,0 +1,23 @@
+#! /bin/sh
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+touch "$DATA_DIR/$CUR_TEST.pnor"
+
+# Don't record the output of ffspart
+../ffspart/ffspart -s 0x1000 -c 10 -i "$DATA_DIR/$CUR_TEST.ffs" \
+ -p "$DATA_DIR/$CUR_TEST.pnor" 2>&1 >/dev/null
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+run_binary "./pflash" "-F $DATA_DIR/$CUR_TEST.pnor --info"
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+#--info will print the name of the file which will change between runs
+sed -i "s|$DATA_DIR/$CUR_TEST.pnor|FILE|" "$STDOUT_OUT"
+
+diff_with_result
+
+pass_test
diff --git a/roms/skiboot/external/pflash/test/tests/02-erase b/roms/skiboot/external/pflash/test/tests/02-erase
new file mode 100644
index 000000000..f1db99266
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/tests/02-erase
@@ -0,0 +1,27 @@
+#! /bin/sh
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+touch "$DATA_DIR/$CUR_TEST.pnor"
+
+# Don't record the output of ffspart
+../ffspart/ffspart -s 0x100 -c 10 -i "$DATA_DIR/$CUR_TEST.ffs" \
+ -p "$DATA_DIR/$CUR_TEST.pnor" 2>&1 >/dev/null
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+yes yes | run_binary "./pflash" "-F $DATA_DIR/$CUR_TEST.pnor -E"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp_with_ff "$DATA_DIR/$CUR_TEST.pnor" 0 \
+ "$(stat --printf="%s" "$DATA_DIR/$CUR_TEST.pnor")"
+
+# The test infrastructure will clean up but lets not chew unnecessarily
+# though disk space
+rm "$DATA_DIR/$CUR_TEST.pnor"
+
+diff_with_result
+
+pass_test
diff --git a/roms/skiboot/external/pflash/test/tests/03-erase-parts b/roms/skiboot/external/pflash/test/tests/03-erase-parts
new file mode 100644
index 000000000..91b0a145e
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/tests/03-erase-parts
@@ -0,0 +1,56 @@
+#! /bin/sh
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+touch "$DATA_DIR/$CUR_TEST.pnor"
+
+# Don't record the output of ffspart
+../ffspart/ffspart -s 0x100 -c 10 -i "$DATA_DIR/$CUR_TEST.ffs" \
+ -p "$DATA_DIR/$CUR_TEST.pnor" 2>&1 >/dev/null
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+cp "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk"
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+#Let us all take a second to appreciate the fragility of this.
+#The reason we need is that pflash -e will set the actual size of the
+#partition to zero, which we'll do here. Examination determined that
+#it will be at byte 216 in the file
+dd if=/dev/zero of="$DATA_DIR/$CUR_TEST.bk" \
+ bs=1 seek=216 count=4 conv=notrunc status=none
+
+#176 Should be where the FFS header for partition ONE starts
+update_checksum "$DATA_DIR/$CUR_TEST.bk" "176";
+
+yes yes | run_binary "./pflash" "-F $DATA_DIR/$CUR_TEST.pnor -e -P ONE"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+one_start=$(get_part_start "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+one_len=$(get_part_len "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+one_end=$(get_part_end "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+cmp_with_ff "$DATA_DIR/$CUR_TEST.pnor" "$one_start" "$one_len"
+
+cmp --bytes="$one_start" "$DATA_DIR/$CUR_TEST.pnor" \
+ "$DATA_DIR/$CUR_TEST.bk";
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp --ignore-initial="$one_end" \
+ --bytes="$(expr $(stat --printf="%s" "$DATA_DIR/$CUR_TEST.pnor") - "$one_end")" \
+ "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+# The test infrastructure will clean up but lets no chew unnecessarily
+# though disk space
+rm "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk"
+
+diff_with_result
+
+pass_test
diff --git a/roms/skiboot/external/pflash/test/tests/04-program-rand b/roms/skiboot/external/pflash/test/tests/04-program-rand
new file mode 100644
index 000000000..fc8abb648
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/tests/04-program-rand
@@ -0,0 +1,55 @@
+#! /bin/sh
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+touch "$DATA_DIR/$CUR_TEST.pnor"
+
+# Don't record the output of ffspart
+../ffspart/ffspart -s 0x100 -c 10 -i "$DATA_DIR/$CUR_TEST.ffs" \
+ -p "$DATA_DIR/$CUR_TEST.pnor" 2>&1 >/dev/null
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+cp "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk"
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+one_len=$(get_part_len "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+one_start=$(get_part_start "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+one_end=$(get_part_end "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+dd if=/dev/urandom bs="$one_len" count=1 of="$DATA_DIR/random" status=none
+
+yes yes | run_binary "./pflash" \
+ "-F $DATA_DIR/$CUR_TEST.pnor -e -P ONE -p $DATA_DIR/random"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp --ignore-initial="$one_start:0" --bytes="$one_len" \
+ "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/random"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp --bytes="$one_start" "$DATA_DIR/$CUR_TEST.pnor" \
+ "$DATA_DIR/$CUR_TEST.bk";
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp --ignore-initial="$one_end" \
+ --bytes="$(expr $(stat --printf="%s" "$DATA_DIR/$CUR_TEST.pnor") - "$one_end")" \
+ "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+sed -i "s|$DATA_DIR/random|FILE|" "$STDOUT_OUT"
+
+# The test infrastructure will clean up but lets no chew unnecessarily
+# though disk space
+rm "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk" "$DATA_DIR/random"
+
+diff_with_result
+
+pass_test
diff --git a/roms/skiboot/external/pflash/test/tests/05-bad-numbers b/roms/skiboot/external/pflash/test/tests/05-bad-numbers
new file mode 100644
index 000000000..03cc39ebf
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/tests/05-bad-numbers
@@ -0,0 +1,66 @@
+#! /bin/sh
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+touch "$DATA_DIR/$CUR_TEST.pnor"
+
+# Don't record the output of ffspart
+../ffspart/ffspart -s 0x100 -c 10 -i "$DATA_DIR/$CUR_TEST.ffs" \
+ -p "$DATA_DIR/$CUR_TEST.pnor" 2>&1 >/dev/null
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+cp "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk"
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+one_len=$(get_part_len "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+one_start=$(get_part_start "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+one_end=$(get_part_end "$DATA_DIR/$CUR_TEST.ffs" "ONE");
+dd if=/dev/urandom bs="$one_len" count=1 of="$DATA_DIR/random" status=none
+
+#This should error out
+run_binary "./pflash" \
+ "-F $DATA_DIR/$CUR_TEST.pnor -e -a NOT_A_NUMBER -s ALSO_NOT_A_NUMBER"
+if [ "$?" -eq 0 ] ; then
+ fail_test;
+fi
+
+one_start_decimal=$(printf "%d" $one_start);
+one_len_decimal=$(printf "%d" $one_len);
+yes yes | run_binary "./pflash" \
+ "-F $DATA_DIR/$CUR_TEST.pnor -e -a $one_start_decimal \
+ -s $one_len_decimal -p $DATA_DIR/random"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp --ignore-initial="$one_start:0" --bytes="$one_len" \
+ "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/random"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp --bytes="$one_start" "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk";
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+cmp --ignore-initial="$one_end" \
+ --bytes="$(expr $(stat --printf="%s" "$DATA_DIR/$CUR_TEST.pnor") - "$one_end")" \
+ "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+sed -i "s|$DATA_DIR/random|FILE|" "$STDOUT_OUT"
+
+# The test infrastructure will clean up but lets no chew unnecessarily
+# though disk space
+rm "$DATA_DIR/$CUR_TEST.pnor" "$DATA_DIR/$CUR_TEST.bk" "$DATA_DIR/random"
+
+strip_version_from_result "pflash"
+
+diff_with_result
+
+pass_test
diff --git a/roms/skiboot/external/pflash/test/tests/06-miscprint b/roms/skiboot/external/pflash/test/tests/06-miscprint
new file mode 100644
index 000000000..bee84afc5
--- /dev/null
+++ b/roms/skiboot/external/pflash/test/tests/06-miscprint
@@ -0,0 +1,46 @@
+#! /bin/sh
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+touch "$DATA_DIR/$CUR_TEST.pnor"
+
+# Don't record the output of ffspart
+../ffspart/ffspart -s 0x1000 -c 10 -i "$DATA_DIR/$CUR_TEST.ffs" \
+ -p "$DATA_DIR/$CUR_TEST.pnor" 2>&1 >/dev/null
+if [ "$?" -ne 0 ] ; then
+ fail_test
+fi
+
+run_binary "./pflash" "--detail=1 -F $DATA_DIR/$CUR_TEST.pnor"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+run_binary "./pflash" "--detail=2 -F $DATA_DIR/$CUR_TEST.pnor"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+run_binary "./pflash" "--detail=3 -F $DATA_DIR/$CUR_TEST.pnor"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+run_binary "./pflash" "--detail=4 -F $DATA_DIR/$CUR_TEST.pnor"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+run_binary "./pflash" "--detail=5 -F $DATA_DIR/$CUR_TEST.pnor"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+run_binary "./pflash" "--detail=6 -F $DATA_DIR/$CUR_TEST.pnor"
+if [ "$?" -ne 0 ] ; then
+ fail_test;
+fi
+
+# The test infrastructure will clean up but lets no chew unnecessarily
+# though disk space
+rm "$DATA_DIR/$CUR_TEST.pnor"
+
+strip_version_from_result "pflash"
+
+diff_with_result
+
+pass_test