Skip to content

Instantly share code, notes, and snippets.

@hanetzer
Created August 18, 2019 01:52
Show Gist options
  • Save hanetzer/68721c63210dd80c9a616d2ce37cd250 to your computer and use it in GitHub Desktop.
Save hanetzer/68721c63210dd80c9a616d2ce37cd250 to your computer and use it in GitHub Desktop.
$ git show;
$ git show
commit 75be152ea7b434fffaa2395dddbd5c1964843f36
Author: Marty E. Plummer <[email protected]>
Date: Sat Aug 17 02:26:58 2019 -0500
util/cbfstool: new utility pnortool
This utility converts plaintext fmd files into pnor headers suitable for
use with open-power systems. Existing systems have seeprom firmware
which looks for this header to locate the hostboot binary and load it
into the processor cache. The tool marks the bootblock as being the
expected HBB hostboot partition.
Change-Id: I6566d86a1e025bfe30aa30da36210f49efde3184
Signed-off-by: Marty E. Plummer <[email protected]>
diff --git a/util/cbfstool/Makefile b/util/cbfstool/Makefile
index d5321f6959..47470f2e5c 100644
--- a/util/cbfstool/Makefile
+++ b/util/cbfstool/Makefile
@@ -12,10 +12,12 @@ OBJCOPY ?= objcopy
VBOOT_SOURCE ?= $(top)/3rdparty/vboot
.PHONY: all
-all: cbfstool ifittool fmaptool rmodtool ifwitool cbfs-compression-tool
+all: cbfstool ifittool fmaptool rmodtool ifwitool cbfs-compression-tool pnortool
cbfstool: $(objutil)/cbfstool/cbfstool
+pnortool: $(objutil)/cbfstool/pnortool
+
fmaptool: $(objutil)/cbfstool/fmaptool
rmodtool: $(objutil)/cbfstool/rmodtool
@@ -26,10 +28,11 @@ ifittool: $(objutil)/cbfstool/ifittool
cbfs-compression-tool: $(objutil)/cbfstool/cbfs-compression-tool
-.PHONY: clean cbfstool ifittool fmaptool rmodtool ifwitool cbfs-compression-tool
+.PHONY: clean cbfstool ifittool fmaptool rmodtool ifwitool cbfs-compression-tool pnortool
clean:
$(RM) fmd_parser.c fmd_parser.h fmd_scanner.c fmd_scanner.h
$(RM) $(objutil)/cbfstool/cbfstool $(cbfsobj)
+ $(RM) $(objutil)/cbfstool/pnortool $(pnorobj)
$(RM) $(objutil)/cbfstool/fmaptool $(fmapobj)
$(RM) $(objutil)/cbfstool/rmodtool $(rmodobj)
$(RM) $(objutil)/cbfstool/ifwitool $(ifwiobj)
@@ -49,6 +52,7 @@ linux_trampoline.c: linux_trampoline.S
install: all
mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL) cbfstool $(DESTDIR)$(BINDIR)
+ $(INSTALL) pnortool $(DESTDIR)$(BINDIR)
$(INSTALL) fmaptool $(DESTDIR)$(BINDIR)
$(INSTALL) rmodtool $(DESTDIR)$(BINDIR)
$(INSTALL) ifwitool $(DESTDIR)$(BINDIR)
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index 95372c2988..f7cb366626 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -42,6 +42,16 @@ cbfsobj += cbfs-payload-linux.o
# compression algorithms
cbfsobj += $(compressionobj)
+pnorobj :=
+pnorobj += pnortool.o
+pnorobj += cbfs_sections.o
+pnorobj += pnor_from_fmd.o
+pnorobj += fmd.o
+pnorobj += fmd_parser.o
+pnorobj += fmd_scanner.o
+# FMAP
+pnorobj += pnor.o
+
fmapobj :=
fmapobj += fmaptool.o
fmapobj += cbfs_sections.o
@@ -110,6 +120,7 @@ TOOLCFLAGS += -Wstrict-prototypes -Wwrite-strings
TOOLCFLAGS += -O2
TOOLCPPFLAGS ?= -D_DEFAULT_SOURCE # memccpy() from string.h
TOOLCPPFLAGS += -D_XOPEN_SOURCE=700 # strdup() from string.h
+TOOLCPPFLAGS += -I$(top)/util/cbfstool/pnor
TOOLCPPFLAGS += -I$(top)/util/cbfstool/flashmap
TOOLCPPFLAGS += -I$(top)/util/cbfstool
TOOLCPPFLAGS += -I$(objutil)/cbfstool
@@ -143,6 +154,10 @@ $(objutil)/cbfstool/%.o: $(top)/util/cbfstool/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
+$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/pnor/%.c
+ printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
+ $(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
+
$(objutil)/cbfstool/%.o: $(top)/util/cbfstool/flashmap/%.c
printf " HOSTCC $(subst $(objutil)/,,$(@))\n"
$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
@@ -171,6 +186,10 @@ $(objutil)/cbfstool/cbfstool: $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
+$(objutil)/cbfstool/pnortool: $(addprefix $(objutil)/cbfstool/,$(pnorobj))
+ printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
+ $(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(pnorobj))
+
$(objutil)/cbfstool/fmaptool: $(addprefix $(objutil)/cbfstool/,$(fmapobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(fmapobj))
diff --git a/util/cbfstool/description.md b/util/cbfstool/description.md
index 63b50f2f12..311fdc3f0a 100644
--- a/util/cbfstool/description.md
+++ b/util/cbfstool/description.md
@@ -3,3 +3,4 @@ __cbfstool__
* _fmaptool_ - Converts plaintext fmd files into fmap blobs `C`
* _rmodtool_ - Creates rmodules `C`
* _ifwitool_ - For manipulating IFWI `C`
+ * _pnortool_ - Converts plaintext fmd files into pnor headers `C`
diff --git a/util/cbfstool/pnor/pnor.c b/util/cbfstool/pnor/pnor.c
new file mode 100644
index 0000000000..8370dbec28
--- /dev/null
+++ b/util/cbfstool/pnor/pnor.c
@@ -0,0 +1,232 @@
+#define _XOPEN_SOURCE 700
+
+#include <commonlib/endian.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pnor.h"
+
+int pnor_size(const struct pnor *pnor)
+{
+ if (!pnor)
+ return -1;
+
+ return sizeof(*pnor) + (pnor->entry_count) * sizeof(struct pnor_area);
+}
+
+static int is_valid_pnor(const struct pnor *pnor)
+{
+ if (memcmp(pnor, PNOR_SIGNATURE, strlen(PNOR_SIGNATURE)) != 0)
+ return 0;
+ if (pnor->version != PNOR_VER)
+ return 0;
+ if (pnor->block_count * pnor->block_size
+ < sizeof(*pnor) + (pnor->entry_count * sizeof(struct pnor_area)))
+ return 0;
+
+ return 1;
+}
+
+static long int pnor_lsearch(const uint8_t *image, size_t len)
+{
+ unsigned long int offset;
+ int pnor_found = 0;
+
+ for (offset = 0; offset < len - strlen(PNOR_SIGNATURE); offset++) {
+ if (is_valid_pnor((const struct pnor *)&image[offset])) {
+ pnor_found = 1;
+ break;
+ }
+ }
+
+ if (!pnor_found)
+ return -1;
+
+ if (offset + pnor_size((const struct pnor *)&image[offset]) > len)
+ return -1;
+
+ return offset;
+}
+
+static long int pnor_bsearch(const uint8_t *image, size_t len)
+{
+ unsigned long int offset = -1;
+ int pnor_found = 0, stride;
+
+ for (stride = len / 2; stride >= 16; stride /= 2) {
+ if (pnor_found)
+ break;
+
+ for (offset = 0; offset < len - strlen(PNOR_SIGNATURE); offset += stride) {
+ if ((offset % (stride * 2) == 0) && (offset != 0))
+ continue;
+ if (is_valid_pnor((const struct pnor *)&image[offset])) {
+ pnor_found = 1;
+ break;
+ }
+ }
+ }
+
+ if (!pnor_found)
+ return -1;
+
+ if (offset + pnor_size((const struct pnor *)&image[offset]) > len)
+ return -1;
+
+ return offset;
+}
+
+static int popcnt(unsigned int u)
+{
+ int count;
+
+ /* K&R method */
+ for (count = 0; u; count++)
+ u &= (u - 1);
+
+ return count;
+}
+
+long int pnor_find(const uint8_t *image, unsigned int len)
+{
+ long int ret = -1;
+ if ((image == NULL) || (len == 0))
+ return -1;
+
+ if (popcnt(len) == 1)
+ ret = pnor_bsearch(image, len);
+ else
+ ret = pnor_lsearch(image, len);
+
+ return ret;
+}
+
+/* int pnor_print(const struct pnor *pnor) */
+/* { */
+/* return 0; */
+/* } */
+
+/* char *pnor_flags_to_string(uint16_t flags) */
+
+struct pnor *pnor_create(uint32_t size)
+{
+ struct pnor *pnor;
+
+ pnor = malloc(sizeof(*pnor));
+ if (!pnor)
+ return NULL;
+
+ memset(pnor, 0, sizeof(*pnor));
+ memcpy(&pnor->magic, PNOR_SIGNATURE, strlen(PNOR_SIGNATURE));
+ pnor->version = PNOR_VER;
+ pnor->size = 2;
+ pnor->entry_size = sizeof(struct pnor_area);
+ pnor->block_size = 0x1000; // hardcode for now
+ pnor->block_count = size / pnor->block_size;
+
+ return pnor;
+}
+
+void pnor_destroy(struct pnor *pnor)
+{
+ free(pnor);
+}
+
+int pnor_append_area(struct pnor **pnor, uint32_t offset, uint32_t size, const uint8_t *name,
+ uint32_t flags)
+{
+ struct pnor_area *area;
+ int orig_size, new_size;
+ uint32_t pid_top = 0xffffffff;
+ uint32_t actual;
+
+ if ((pnor == NULL || *pnor == NULL) || (name == NULL))
+ return -1;
+
+ if ((*pnor)->entry_count >= 0x10000)
+ return -1;
+
+ actual = size;
+ size /= (*pnor)->block_size;
+ offset /= (*pnor)->block_size;
+ orig_size = pnor_size(*pnor);
+ new_size = orig_size + sizeof(*area);
+
+ *pnor = realloc(*pnor, new_size);
+ if (*pnor == NULL)
+ return -1;
+
+ area = (struct pnor_area *)((uint8_t *)*pnor + orig_size);
+ memset(area, 0, sizeof(*area));
+ memcpy(&area->base, &offset, sizeof(area->base));
+ memcpy(&area->size, &size, sizeof(area->size));
+ memcpy(&area->pid, &pid_top, sizeof(area->pid));
+ if (strcmp((const char *)name, "BOOTBLOCK") != 0)
+ memccpy(&area->name, name, '\0', PNOR_STRLEN);
+ else
+ memccpy(&area->name, "HBB", '\0', PNOR_STRLEN);
+ memcpy(&area->flags, &flags, sizeof(area->flags));
+ memcpy(&area->actual, &actual, sizeof(area->actual));
+
+ (*pnor)->entry_count++;
+ return new_size;
+}
+
+const struct pnor_area *pnor_find_area(const struct pnor *pnor, const char *name)
+{
+ unsigned int i;
+ const struct pnor_area *area = NULL;
+
+ if (!pnor || !name)
+ return NULL;
+
+ for (i = 0; i < pnor->entry_count; i++) {
+ if (!strcmp((const char *)pnor->areas[i].name, name)) {
+ area = &pnor->areas[i];
+ break;
+ }
+ }
+
+ return area;
+}
+
+static uint32_t checksum(void *data, size_t size)
+{
+ uint32_t i, csum = 0;
+
+ for (i = csum = 0; i < (size / 4); i++)
+ csum ^= ((uint32_t *)data)[i];
+ return csum;
+}
+
+uint32_t pnor_checksum(struct pnor *pnor)
+{
+ return checksum(pnor, sizeof(struct pnor));
+}
+
+uint32_t pnor_area_checksum(struct pnor_area *pnor_area)
+{
+ return checksum(pnor_area, sizeof(struct pnor_area));
+}
+
+void pnor_finalize(struct pnor *pnor)
+{
+ for (uint32_t i = 0; i < pnor->entry_count; i++) {
+ write_be32(&pnor->areas[i].base, pnor->areas[i].base);
+ write_be32(&pnor->areas[i].size, pnor->areas[i].size);
+ write_be32(&pnor->areas[i].pid, pnor->areas[i].pid);
+ write_be32(&pnor->areas[i].id, i + 1);
+ write_be32(&pnor->areas[i].type, pnor->areas[i].type);
+ write_be32(&pnor->areas[i].checksum, pnor_area_checksum(&pnor->areas[i]));
+ }
+
+ write_be32(&pnor->version, pnor->version);
+ write_be32(&pnor->size, pnor->size);
+ write_be32(&pnor->entry_size, pnor->entry_size);
+ write_be32(&pnor->entry_count, pnor->entry_count);
+ write_be32(&pnor->block_size, pnor->block_size);
+ write_be32(&pnor->block_count, pnor->block_count);
+ write_be32(&pnor->checksum, pnor_checksum(pnor));
+}
diff --git a/util/cbfstool/pnor/pnor.h b/util/cbfstool/pnor/pnor.h
new file mode 100644
index 0000000000..cb32146fcc
--- /dev/null
+++ b/util/cbfstool/pnor/pnor.h
@@ -0,0 +1,148 @@
+#ifndef PNOR_LIB_PNOR_H__
+#define PNOR_LIB_PNOR_H__
+
+#include <endian.h>
+#include <inttypes.h>
+
+#define PNOR_SIGNATURE "PART"
+#define PNOR_VER 1
+#define PNOR_STRLEN 16
+#define PNOR_BOOTBLOCK "BOOTBLOCK"
+#define PNOR_PID_TOPLEVEL 0xFFFFFFFF
+
+struct pnor_area_user {
+ uint8_t chip;
+ uint8_t compresstype;
+ uint16_t datainteg;
+ uint8_t vercheck;
+ uint8_t miscflags;
+ uint8_t freemisc[2];
+ uint32_t reserved[14];
+} __packed;
+
+struct pnor_area {
+ uint8_t name[PNOR_STRLEN];
+ uint32_t base;
+ uint32_t size;
+ uint32_t pid;
+ uint32_t id;
+ uint32_t type;
+ uint32_t flags;
+ uint32_t actual;
+ uint32_t resvd[4];
+ struct pnor_area_user user;
+ uint32_t checksum;
+} __packed;
+
+struct pnor {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t size;
+ uint32_t entry_size;
+ uint32_t entry_count;
+ uint32_t block_size;
+ uint32_t block_count;
+ uint32_t resvd[4];
+ uint32_t checksum;
+ struct pnor_area areas[];
+} __packed;
+
+/**
+ * pnor_find - find PNOR signature in a binary image
+ *
+ * @image: binary image
+ * @len: length of binary image
+ *
+ * This function does no error checking. The caller is responsible for
+ * verifying that the contents are sane.
+ *
+ * returns offset of PNOR signature to indicate success
+ * returns <0 to indicate failure
+ */
+extern long int pnor_find(const uint8_t *image, unsigned int len);
+
+/**
+ * pnor_print - Print contents of pnor data structure
+ *
+ * @map: raw map data
+ *
+ * returns 0 to indicate success
+ * returns <0 to indicate failure
+ */
+/* extern int pnor_print(const struct pnor *pnor); */
+
+/**
+ * pnor_flags_to_string - convert raw flags field into user-friendly string
+ *
+ * @flags: raw flags
+ *
+ * This function returns a user-friendly comma-separated list of pnor area
+ * flags. If there are no flags (flags == 0), the string will contain only
+ * a terminating character ('\0')
+ *
+ * This function allocates memory which the caller must free.
+ *
+ * returns pointer to an allocated string if successful
+ * returns NULL to indicate failure
+ */
+char *pnor_flags_to_string(uint32_t flags);
+
+/**
+ * pnor_create - allocate and initialize a new pnor structure
+ *
+ * @size: size of the fimware (bytes)
+ *
+ * This function will allocate a pnor header. Members of the structure
+ * which are not passed in are automatically initialized.
+ *
+ * returns pointer to newly allocated flashmap header if successful
+ * returns NULL to indicate failure.
+ */
+extern struct pnor *pnor_create(uint32_t size);
+
+/* free memory used by a pnor structure */
+extern void pnor_destroy(struct pnor *pnor);
+
+/**
+ * pnor_size - returns size of the pnor data structure (including areas)
+ *
+ * @pnor: pnor
+ *
+ * returns size of pnor structure if successful
+ * returns <0 to indicate failure
+ */
+extern int pnor_size(const struct pnor *pnor);
+
+/**
+ * pnor_append_area - realloc an existing pnor and append an area
+ *
+ * @pnor: double pointer to existing pnor
+ * @offset: offset of area
+ * @size: size of area
+ * @name: name of area
+ * @flags: area flags
+ *
+ * returns total size of reallocated pnor structure if successful
+ * returns <0 to indicate failure
+ */
+extern int pnor_append_area(struct pnor **pnor, uint32_t offset, uint32_t size,
+ const uint8_t *name, uint32_t flags);
+
+/**
+ * pnor_find_area - find a pnor_area entry (by name) and return pointer to it
+ *
+ * @pnor: pnor structure to parse
+ * @name: name of area to find
+ *
+ * returns a pointer to the entry in the pnor structure if successfull
+ * returns NULL to indicate failure or if no matching area is found
+ */
+extern const struct pnor_area *pnor_find_area(const struct pnor *pnor, const char *name);
+
+/* unit testing stuff */
+extern int pnor_test(void);
+
+extern uint32_t pnor_checksum(struct pnor *pnor);
+extern uint32_t pnor_area_checksum(struct pnor_area *pnor_area);
+extern void pnor_finalize(struct pnor *pnor);
+#endif /* PNOR_LIB_PNOR_H__*/
diff --git a/util/cbfstool/pnor_from_fmd.c b/util/cbfstool/pnor_from_fmd.c
new file mode 100644
index 0000000000..ba81875de3
--- /dev/null
+++ b/util/cbfstool/pnor_from_fmd.c
@@ -0,0 +1,63 @@
+#include "pnor_from_fmd.h"
+
+#include "common.h"
+
+#include <assert.h>
+#include <string.h>
+
+static bool pnor_append_fmd_node(struct pnor **pnor, const struct flashmap_descriptor *section,
+ unsigned absolute_watermark)
+{
+ uint32_t flags = 0;
+ if (strlen(section->name) >= PNOR_STRLEN) {
+ ERROR("Section name ('%s') exceeds %d character PNOR format limit\n",
+ section->name, PNOR_STRLEN - 1);
+ return false;
+ }
+
+ absolute_watermark += section->offset;
+
+ if (pnor_append_area(pnor, absolute_watermark, section->size, (uint8_t *)section->name,
+ flags)
+ < 0) {
+ ERROR("Failed to insert section '%s' into PNOR\n", section->name);
+ return false;
+ }
+
+ fmd_foreach_child(subsection, section)
+ {
+ if (!pnor_append_fmd_node(pnor, subsection, absolute_watermark))
+ return false;
+ }
+
+ return true;
+}
+
+struct pnor *pnor_from_fmd(const struct flashmap_descriptor *desc)
+{
+ assert(desc);
+ assert(desc->size_known);
+
+ if (strlen(desc->name) >= PNOR_STRLEN) {
+ ERROR("Image name ('%s') exceeds %d character PNOR header limite\n", desc->name,
+ PNOR_STRLEN - 1);
+ return NULL;
+ }
+
+ struct pnor *pnor = pnor_create(desc->size);
+
+ if (!pnor) {
+ ERROR("Failed to allocate PNOR header\n");
+ return pnor;
+ }
+
+ fmd_foreach_child(real_section, desc)
+ {
+ if (!pnor_append_fmd_node(&pnor, real_section, 0)) {
+ pnor_destroy(pnor);
+ return NULL;
+ }
+ }
+
+ return pnor;
+}
diff --git a/util/cbfstool/pnor_from_fmd.h b/util/cbfstool/pnor_from_fmd.h
new file mode 100644
index 0000000000..5df87b4de9
--- /dev/null
+++ b/util/cbfstool/pnor_from_fmd.h
@@ -0,0 +1,14 @@
+#ifndef PNOR_FROM_FMD_H_
+#define PNOR_FROM_FMD_H_
+
+#include "pnor/pnor.h"
+#include "fmd.h"
+
+/**
+ * @param desc The descriptor tree serving as a data source
+ * @return The PNOR section, which is owned by the caller and must
+ * later be released with a call to pnor_destroy()
+ */
+struct pnor *pnor_from_fmd(const struct flashmap_descriptor *desc);
+
+#endif /* PNOR_FROM_FMD_H */
diff --git a/util/cbfstool/pnortool.c b/util/cbfstool/pnortool.c
new file mode 100644
index 0000000000..7d5089ff08
--- /dev/null
+++ b/util/cbfstool/pnortool.c
@@ -0,0 +1,157 @@
+#include "common.h"
+#include "cbfs_sections.h"
+#include "pnor_from_fmd.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define STDIN_FILENAME_SENTINEL "-"
+
+enum pnortool_return {
+ PNORTOOL_EXIT_SUCCESS = 0,
+ PNORTOOL_EXIT_BAD_ARGS,
+ PNORTOOL_EXIT_BAD_INPUT_PATH,
+ PNORTOOL_EXIT_BAD_OUTPUT_PATH,
+ PNORTOOL_EXIT_FAILED_DESCRIPTOR,
+ PNORTOOL_EXIT_MISSING_FMAP_SECTION,
+ PNORTOOL_EXIT_MISSING_PRIMARY_CBFS,
+ PNORTOOL_EXIT_FAILED_PNOR_CONVERSION,
+ PNORTOOL_EXIT_UNKNOWN_PNOR_SIZE,
+ PNORTOOL_EXIT_FAILED_WRITING_OUTPUT,
+};
+
+static void usage(const char *invoked_as)
+{
+ fputs("pnortool: Transpiler for fmd (flashmap descriptor) files\n", stderr);
+ fputs("\nUSAGE:\n", stderr);
+ fprintf(stderr, "\t%s: [-b] [-h] <fmd input file> <binary output file>\n", invoked_as);
+ fputs("\nMANDATORY ARGUMENTS:\n", stderr);
+ fprintf(stderr, "<fmd input file> may be '%s' to read from standard input\n",
+ STDIN_FILENAME_SENTINEL);
+ fputs("<binary output file> must be a regular file\n", stderr);
+ fputs("\nOPTIONAL SWITCHES:\n", stderr);
+ fputs("-b\tProduce a pnor header suitable for use as a backup header\n", stderr);
+ fputs("-h\tShow this usage message\n", stderr);
+}
+
+static void full_fmd_cleanup(struct flashmap_descriptor **victim)
+{
+ assert(victim);
+
+ cbfs_sections_cleanup();
+ fmd_cleanup(*victim);
+ *victim = NULL;
+}
+
+int main(int argc, char **argv)
+{
+ struct {
+ // Manditory
+ const char *fmd_filename;
+ const char *pnor_filename;
+ // Optional
+ bool backup;
+ } args = {NULL, NULL, false};
+
+ bool show_usage = false;
+ int each_arg;
+ while (!show_usage && (each_arg = getopt(argc, argv, ":hb")) != -1) {
+ switch (each_arg) {
+ case 'h':
+ show_usage = true;
+ break;
+ case 'b':
+ args.backup = true;
+ break;
+ default:
+ fprintf(stderr, "-%c: Unexpected command-line switch\n", optopt);
+ show_usage = true;
+ }
+ }
+
+ if (show_usage || argc - optind != 2) {
+ usage(argv[0]);
+ return PNORTOOL_EXIT_BAD_ARGS;
+ }
+ args.fmd_filename = argv[optind];
+ args.pnor_filename = argv[optind + 1];
+
+ FILE *fmd_file = stdin;
+ if (strcmp(args.fmd_filename, STDIN_FILENAME_SENTINEL) != 0) {
+ fmd_file = fopen(args.fmd_filename, "r");
+ if (!fmd_file) {
+ fprintf(stderr, "FATAL: Unable to open file '%s'\n", args.fmd_filename);
+ return PNORTOOL_EXIT_BAD_INPUT_PATH;
+ }
+ }
+
+ struct flashmap_descriptor *descriptor = fmd_create(fmd_file);
+ fclose(fmd_file);
+ if (!descriptor) {
+ fputs("FATAL: Failed while processing provided descriptor\n", stderr);
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_FAILED_DESCRIPTOR;
+ }
+
+ if (!fmd_find_node(descriptor, SECTION_NAME_FMAP)) {
+ fprintf(stderr, "FATAL: Flashmap descriptor must have an '%s' section\n",
+ SECTION_NAME_FMAP);
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_MISSING_FMAP_SECTION;
+ }
+
+ if (!cbfs_sections_primary_cbfs_accounted_for()) {
+ fprintf(stderr,
+ "FATAL: Flashmap descriptor must have a '%s' section that is annoted with '%s)'\n",
+ SECTION_NAME_PRIMARY_CBFS, SECTION_ANNOTATION_CBFS);
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_MISSING_PRIMARY_CBFS;
+ }
+
+ struct pnor *pnor = pnor_from_fmd(descriptor);
+ if (!pnor) {
+ fputs("FATAL: Failed while constructing PNOR section\n", stderr);
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_FAILED_PNOR_CONVERSION;
+ }
+
+ int size = pnor_size(pnor);
+ if (size < 0) {
+ fputs("FATAL: Failed to determine PNOR section size\n", stderr);
+ pnor_destroy(pnor);
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_UNKNOWN_PNOR_SIZE;
+ }
+
+ if (args.backup) {
+ uint32_t tmp = pnor->areas[0].base;
+ pnor->areas[0].base = pnor->areas[pnor->entry_count - 1].base;
+ pnor->areas[pnor->entry_count - 1].base = tmp;
+ }
+ pnor_finalize(pnor);
+
+ FILE *pnor_file = fopen(args.pnor_filename, "wb");
+ if (!pnor_file) {
+ fprintf(stderr, "FATAL: Unable to open file '%s' for writing\n",
+ args.pnor_filename);
+ pnor_destroy(pnor);
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_BAD_OUTPUT_PATH;
+ }
+
+ if (!fwrite(pnor, size, 1, pnor_file)) {
+ fputs("FATAL: Failed to write final PNOR to file\n", stderr);
+ fclose(pnor_file);
+ pnor_destroy(pnor);
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_FAILED_WRITING_OUTPUT;
+ }
+ fclose(pnor_file);
+ pnor_destroy(pnor);
+
+ fprintf(stderr, "SUCCESS: Wrote %d bytes to file '%s'\n", size, args.pnor_filename);
+
+ full_fmd_cleanup(&descriptor);
+ return PNORTOOL_EXIT_SUCCESS;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment