new file mode 100644
@@ -0,0 +1,40 @@
+# Use make V=1 for a verbose build.
+GET_ARCH = ../../external/common/get_arch.sh
+include ../../external/common/rules.mk
+include rules.mk
+
+all: $(EXE)
+
+.PHONY: links
+links: libflash ccan common
+
+$(OBJS): | links arch_links
+
+.PHONY: VERSION-always
+.version: VERSION-always
+ @echo $(FFSPART_VERSION) > $@.tmp
+ @cmp -s $@ $@.tmp || cp $@.tmp $@
+ @rm -f $@.tmp
+
+install: all
+ install -D ffspart $(DESTDIR)$(sbindir)/ffspart
+
+.PHONY: dist
+#File is named $(FFSPART_VERSION).tar because the expectation is that ffspart-
+#is always at the start of the verion. This remains consistent with skiboot
+#version strings
+dist: links .version
+ find -L ../ffspart/ -iname '*.[ch]' -print0 | xargs -0 tar -rhf $(FFSPART_VERSION).tar
+ tar --transform 's/Makefile.dist/Makefile/' -rhf $(FFSPART_VERSION).tar \
+ ../ffspart/Makefile.dist ../ffspart/rules.mk \
+ ../ffspart/.version ../ffspart/make_version.sh \
+ ../ffspart/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 .version.tmp
+ rm -f common io.h
new file mode 100644
@@ -0,0 +1,336 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <libflash/libflash.h>
+#include <libflash/libffs.h>
+#include <libflash/blocklevel.h>
+#include <common/arch_flash.h>
+
+/*
+ * Flags:
+ * - E: ECC for this part
+ */
+
+/*
+ * TODO FIXME
+ * Max line theoretical max size:
+ * - name: 15 chars = 15
+ * - base: 0xffffffff = 10
+ * - size: 0xffffffff = 10
+ * - flag: E = 1
+ *
+ * 36 + 3 separators = 39
+ * Plus \n 40
+ * Lets do 50.
+ */
+#define MAX_LINE 100
+#define SEPARATOR ','
+/* Full version number (possibly includes gitid). */
+extern const char version[];
+
+static void print_version(void)
+{
+ printf("Open-Power FFS format tool %s\n", version);
+}
+
+static void print_help(const char *pname)
+{
+ print_version();
+ printf("Usage: %s [options] commands...\n\n", pname);
+ printf(" Options:\n");
+ printf("\t-b, --block_size=size\n");
+ printf("\t\tSize (in hex with leading 0x) of the blocks on the flash in bytes\n\n");
+ printf("\t-c, --block_count=num\n");
+ printf("\t\tNumber of blocks on the flash\n\n");
+ printf("\t-i, --input=file\n");
+ printf("\t\tFile containing the required partition data\n\n");
+ printf("\t-p, -pnor=file\n");
+ printf("\t\tOutput file to write data\n\n");
+ printf("\t-s, -size=size\n");
+ printf("\t\tSize (in hex with leading 0x) of the partition table in bytes\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+ const char *pname = argv[0];
+ struct blocklevel_device *bl = NULL;
+ uint32_t size = 0, block_size = 0, block_count = 0;
+ char *pnor = NULL, *input = NULL;
+ struct ffs_hdr *new_hdr;
+ FILE *in_file;
+ char line[MAX_LINE];
+ int rc;
+
+ while(1) {
+ struct option long_opts[] = {
+ {"block_size", required_argument, NULL, 'b'},
+ {"block_count", required_argument, NULL, 'c'},
+ {"input", required_argument, NULL, 'i'},
+ {"pnor", required_argument, NULL, 'p'},
+ {"size", required_argument, NULL, 's'},
+ };
+ int c, oidx = 0;
+
+ c = getopt_long(argc, argv, "b:c:i:p:s:", long_opts, &oidx);
+ if (c == EOF)
+ break;
+ switch(c) {
+ case 'b':
+ block_size = strtoul(optarg, NULL, 0);
+ break;
+ case 'c':
+ block_count = strtoul(optarg, NULL, 0);
+ break;
+ case 'i':
+ input = strdup(optarg);
+ break;
+ case 'p':
+ pnor = strdup(optarg);
+ break;
+ case 's':
+ size = strtoul(optarg, NULL, 0);
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ if (!block_size || !block_count || !input || !pnor || !size) {
+ print_help(pname);
+ rc = 1;
+ goto out;
+ }
+
+ rc = ffs_hdr_new(size, block_size, block_count, &new_hdr);
+ if (rc) {
+ if (rc == FFS_ERR_BAD_SIZE) {
+ fprintf(stderr, "Bad size parametres passed to libffs: "
+ "size must be a multiple of block_size\n"
+ "size (%u), block_size (%u) \n", size, block_size);
+ } else {
+ fprintf(stderr, "Error %d initialising new TOC\n", rc);
+ }
+ goto out;
+ }
+
+ in_file = fopen(input, "r");
+ if (!in_file) {
+ rc = errno;
+ fprintf(stderr, "Couldn't open your input file %s because %s\n", input, strerror(errno));
+ goto out_free_hdr;
+ }
+
+ rc = arch_flash_init(&bl, pnor, true);
+ if (rc) {
+ fprintf(stderr, "Couldn't initialise architecture flash structures\n");
+ goto out_close_f;
+ }
+
+ while (fgets(line, MAX_LINE, in_file) != NULL) {
+ struct ffs_entry *new_entry;
+ struct ffs_entry_user user = { 0 };
+ char *pos, *old_pos;
+ char *name;
+ uint32_t pbase, psize, pactual = 0;
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ pos = strchr(line, SEPARATOR);
+ if (!pos) {
+ fprintf(stderr, "Invalid input file format: Couldn't find name\n");
+ goto out_close_bl;
+ }
+ *pos = '\0';
+ name = line;
+
+ pos++;
+ old_pos = pos;
+ pos = strchr(pos, SEPARATOR);
+ if (!pos) {
+ fprintf(stderr, "Invalid input file format: Couldn't find base\n");
+ goto out_close_bl;
+ }
+ *pos = '\0';
+ pbase = strtoul(old_pos, NULL, 0);
+
+ pos++;
+ old_pos = pos;
+ pos = strchr(pos, SEPARATOR);
+ if (!pos) {
+ fprintf(stderr, "Invalid input file format: Couldn't find size\n");
+ goto out_close_bl;
+ }
+ *pos = '\0';
+ psize = strtoul(old_pos, NULL, 0);
+
+ pos++;
+ while (*pos != '\0' && *pos != SEPARATOR) {
+ switch (*pos) {
+ case 'E':
+ user.datainteg |= FFS_ENRY_INTEG_ECC;
+ break;
+ case 'V':
+ user.vercheck |= FFS_VERCHECK_SHA512V;
+ break;
+ case 'I':
+ user.vercheck |= FFS_VERCHECK_SHA512EC;
+ break;
+ case 'P':
+ user.miscflags |= FFS_MISCFLAGS_PRESERVED;
+ break;
+ case 'R':
+ user.miscflags |= FFS_MISCFLAGS_READONLY;
+ break;
+ case 'F':
+ user.miscflags |= FFS_MISCFLAGS_REPROVISION;
+ break;
+ /* Not sure these are valid */
+ case 'B':
+ user.miscflags |= FFS_MISCFLAGS_BACKUP;
+ break;
+ default:
+ fprintf(stderr, "Unknown flag '%c'\n", *pos);
+ }
+ pos++;
+ }
+
+ printf("Adding '%s' 0x%08x, 0x%08x\n", name, pbase, psize);
+ rc = ffs_entry_new(name, pbase, psize, &new_entry);
+ if (rc) {
+ fprintf(stderr, "Invalid entry '%s' 0x%08x for 0x%08x\n",
+ name, pbase, psize);
+ goto out_close_bl;
+ }
+
+ rc = ffs_entry_user_set(new_entry, &user);
+ if (rc) {
+ fprintf(stderr, "Invalid flag passed to ffs_entry_user_set\n");
+ goto out_close_bl;
+ }
+
+ rc = ffs_entry_add(new_hdr, new_entry);
+ if (rc) {
+ fprintf(stderr, "Couldn't add entry '%s' 0x%08x for 0x%08x\n",
+ name, pbase, psize);
+ goto out_close_bl;
+ }
+
+ if (*pos != '\0') {
+ struct stat data_stat;
+ int data_fd, rc;
+ uint8_t *data_ptr;
+ char *data_fname = pos + 1;
+
+ data_fd = open(data_fname, O_RDONLY);
+ if (data_fd == -1) {
+ fprintf(stderr, "Couldn't open data file for partition '%s' (filename: %s)\n",
+ name, data_fname);
+ goto out_close_bl;
+ }
+
+ if (fstat(data_fd, &data_stat) == -1) {
+ fprintf(stderr, "Couldn't stat data file for partition '%s': %s\n",
+ name, strerror(errno));
+ close(data_fd);
+ goto out_close_bl;
+ }
+ pactual = data_stat.st_size;
+
+ /*
+ * Sanity check that the file isn't too large for
+ * partition
+ */
+ if (pactual > psize) {
+ fprintf(stderr, "Data file for partition '%s' is too large\n",
+ name);
+ close(data_fd);
+ goto out_close_bl;
+ }
+
+ data_ptr = mmap(NULL, pactual, PROT_READ, MAP_SHARED, data_fd, 0);
+ if (!data_ptr) {
+ fprintf(stderr, "Couldn't mmap data file for partition '%s': %s\n",
+ name, strerror(errno));
+ close(data_fd);
+ goto out_close_bl;
+ }
+
+ rc = blocklevel_write(bl, pbase, data_ptr, pactual);
+ if (rc) {
+ fprintf(stderr, "Couldn't write data file for partition '%s' to pnor file: %s\n",
+ name, strerror(errno));
+ munmap(data_ptr, pactual);
+ close(data_fd);
+ goto out_close_bl;
+ }
+
+ munmap(data_ptr, pactual);
+ close(data_fd);
+
+ /*
+ * TODO: Update the actual size within the partition table.
+ */
+ }
+
+ /*
+ * Fill partition with 0xFF bytes.
+ * TODO: Add sparse option and don't do this.
+ */
+ if (pactual < psize) {
+ int pos = pbase + pactual;
+ while (pos < pbase + psize) {
+ int data = UINT_MAX;
+ rc = blocklevel_write(bl, pos, &data,
+ (pbase + psize) - pos > sizeof(int) ? sizeof(int) : (pbase + psize) - pos);
+ if (rc) {
+ fprintf(stderr, "Couldn't write data filling data for partition '%s'\n", name);
+ goto out_close_bl;
+ }
+
+ pos += sizeof(int);
+ }
+ }
+ }
+
+ rc = ffs_hdr_finalise(bl, new_hdr);
+ if (rc)
+ fprintf(stderr, "Failed to write out TOC values");
+
+out_close_bl:
+ arch_flash_close(bl, pnor);
+out_close_f:
+ fclose(in_file);
+out_free_hdr:
+ ffs_hdr_free(new_hdr);
+out:
+ free(input);
+ free(pnor);
+ return rc;
+}
new file mode 100644
@@ -0,0 +1,33 @@
+.DEFAULT_GOAL := all
+
+override CFLAGS += -O2 -Wall -g -I.
+EXE = ffspart
+OBJS = $(EXE).o version.o
+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))
+OBJS += $(LIBFLASH_OBJS)
+OBJS += common-arch_flash.o
+
+CC = $(CROSS_COMPILE)gcc
+
+FFSPART_VERSION ?= $(shell ../../make_version.sh $(EXE))
+
+version.c: .version
+ @(if [ "a$(FFSPART_VERSION)" = "a" ]; then \
+ echo "#error You need to set FFSPART_VERSION environment variable" > $@ ;\
+ else \
+ echo "const char version[] = \"$(FFSPART_VERSION)\";" ;\
+ fi) > $@
+
+%.o : %.c
+ $(Q_CC)$(CC) $(CFLAGS) -c $< -o $@
+
+$(LIBFLASH_SRC): | links
+
+$(LIBFLASH_OBJS): libflash-%.o : libflash/%.c
+ $(Q_CC)$(CC) $(CFLAGS) -c $< -o $@
+
+$(EXE): $(OBJS)
+ $(Q_CC)$(CC) $(CFLAGS) $^ -lrt -o $@
+
A typical input file to generate something that current op-build would create: HBI,0x00010000,0x05a0000,EV,./bins/HBI.bin MVPD,0x05b0000,0x0090000,EF,./bins/MVPD.bin CVPD,0x0640000,0x0048000,EF,./bins/CVPD.bin DJVPD,0x688000,0x0048000,EF,./bins/DJVPD.bin HBD,0x006d0000,0x0060000,E,./bins/HBD.bin SBEC,0x0730000,0x0090000,EI,./bins/SBEC.bin SBE,0x007c0000,0x0048000,EI,./bins/SBE.bin ATTR_TMP,0x808000,0x8000,F,./bins/ATTR_TMP.bin ATTR_PERM,0x810000,0x8000,EF,./bins/ATTR_PERM.bin WINK,0x00818000,0x0120000,EV,./bins/WINK.bin GUARD,0x00938000,0x005000,EPF,./bins/GUARD.bin HBEL,0x0093d000,0x0024000,EF,./bins/HBEL.bin PAYLOAD,0x961000,0x100000,,./bins/skiboot.lid BOOTKERNEL,0xa61000,0xf00000,,./bins/petitboot.zImage NVRAM,0x01961000,0x90000,EPF,./bins/NVRAM.bin HBRT,0x019f1000,0x360000,EV,./bins/HBRT.bin OCC,0x001d51000,0x120000,E,./bins/OCC.bin FIRDATA,0x1e71000,0x3000,EF,./bins/FIRDATA.bin CAPP,0x001e74000,0x24000,E,./bins/CAPP.bin HBB,0x0001f67000,0x90000,EV,./bins/HBB.bin VERSION,0x1ff7000,0x1000,,./bins/VERSION2.bin BACKUP_PART,0x1ff8000,0x8000,B Signed-off-by: Cyril Bur <cyril.bur@au1.ibm.com> --- external/ffspart/Makefile | 40 ++++++ external/ffspart/ffspart.c | 336 +++++++++++++++++++++++++++++++++++++++++++++ external/ffspart/rules.mk | 33 +++++ 3 files changed, 409 insertions(+) create mode 100644 external/ffspart/Makefile create mode 100644 external/ffspart/ffspart.c create mode 100644 external/ffspart/rules.mk