Add Firmware Image Package creation tool
authorHarry Liebel <Harry.Liebel@arm.com>
Fri, 10 Jan 2014 18:00:33 +0000 (18:00 +0000)
committerDan Handley <dan.handley@arm.com>
Mon, 17 Feb 2014 18:51:43 +0000 (18:51 +0000)
This tool can be used to create a Firmware Image Packages (FIP). These
FIPs store a combined set of firmware images with a Table of Contents
(ToC) that can be loaded by the firmware from platform storage.

- Add uuid.h from FreeBSD.
- Use symbolic links to shared headers otherwise unwanted headers and
  definitions are pulled in.
- A FIP is created as part of the default FVP build.
- A BL3-3 image(e.g. UEFI) must be provided.

Change-Id: Ib73feee181df2dba68bf6abec115a83cfa5e26cb

Makefile
include/firmware_image_package.h [new file with mode: 0644]
include/stdlib/sys/uuid.h [new file with mode: 0644]
tools/fip_create/Makefile [new file with mode: 0644]
tools/fip_create/fip_create.c [new file with mode: 0644]
tools/fip_create/fip_create.h [new file with mode: 0644]
tools/fip_create/firmware_image_package.h [new symlink]
tools/fip_create/uuid.h [new symlink]

index f71e6c5b3d979029540beb7c60cb10831d63a769..1ebc172a8d427317cb6f31d2904a8e82fe72c212 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -87,7 +87,7 @@ endif
 ifeq (${PLAT},all)
 all: ${PLATFORMS}
 else
-all: msg_start bl1 bl2 bl31
+all: msg_start bl1 bl2 bl31 fip
 endif
 
 msg_start:
@@ -107,7 +107,7 @@ ifneq (${PLAT},all)
   include bl31/bl31.mk
 endif
 
-.PHONY:                        all msg_start ${PLATFORMS} dump clean realclean distclean bl1 bl2 bl31 cscope locate-checkpatch checkcodebase checkpatch
+.PHONY:                        all msg_start ${PLATFORMS} dump clean realclean distclean bl1 bl2 bl31 cscope locate-checkpatch checkcodebase checkpatch fiptool fip locate-bl33
 .SUFFIXES:
 
 
@@ -179,6 +179,12 @@ bl31:                      ${BUILD_BL31} ${BUILD_PLAT}/bl31.bin
 
 BASE_COMMIT            ?=      origin/master
 
+# Variables for use with Firmware Image Package
+FIPTOOLPATH            ?=      tools/fip_create
+FIPTOOL                ?=      ${FIPTOOLPATH}/fip_create
+fiptool:               ${FIPTOOL}
+fip:                   ${BUILD_PLAT}/fip.bin
+
 ifeq (${PLAT},all)
   ifeq (${MAKECMDGOALS},clean)
     $(error "Please select a platform with PLAT=<platform>. You can use 'make distclean' to clean up all platform builds")
@@ -194,14 +200,26 @@ ifeq (,$(wildcard ${CHECKPATCH}))
 endif
 endif
 
+locate-bl33:
+ifndef BL33
+       $(error "Please set BL33 to point to the Normal World binary, eg: BL33=../uefi/FVP_AARCH64_EFI.fd")
+else
+ifeq (,$(wildcard ${BL33}))
+       $(error "The file BL33 points to cannot be found (${BL33})")
+endif
+endif
+
+
 clean:
                        @echo "  CLEAN"
                        ${Q}rm -rf ${BUILD_PLAT}
+                       ${Q}make -C ${FIPTOOLPATH} clean
 
 realclean distclean:
                        @echo "  REALCLEAN"
                        ${Q}rm -rf ${BUILD_BASE}
                        ${Q}rm -f ${CURDIR}/cscope.*
+                       ${Q}make -C ${FIPTOOLPATH} clean
 
 dump:
                        @echo "  OBJDUMP"
@@ -221,6 +239,12 @@ checkpatch:                locate-checkpatch
                        @echo "  CHECKING STYLE"
                        @git format-patch --stdout ${BASE_COMMIT} | ${CHECKPATCH} ${CHECKPATCH_ARGS} - || true
 
+${FIPTOOL}:
+                       @echo "  BUILDING FIRMWARE IMAGE PACKAGE TOOL $@"
+                       @echo
+                       ${Q}make -C ${FIPTOOLPATH}
+                       @echo
+
 ${BUILD_DIRS}:
                        ${Q}mkdir -p "$@"
 
@@ -295,6 +319,17 @@ ${BUILD_PLAT}/bl31.bin:    ${BUILD_BL31}/bl31.elf
                        @echo "Built $@ successfully"
                        @echo
 
+${BUILD_PLAT}/fip.bin: bl2 bl31 locate-bl33 ${FIPTOOL}
+                       @echo " CREATE FIRMWARE IMAGE PACKAGE $@"
+                       @echo
+                       ${Q}${FIPTOOL} --dump \
+                               --bl2 ${BUILD_PLAT}/bl2.bin \
+                               --bl31 ${BUILD_PLAT}/bl31.bin \
+                               --bl33 ${BL33} \
+                               $@
+                       @echo
+
+
 cscope:
        @echo "  CSCOPE"
        ${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
@@ -314,9 +349,10 @@ help:
        @echo "  checkpatch     Check the coding style on changes in the current"
        @echo "                 branch against BASE_COMMIT (default origin/master)"
        @echo "  clean          Clean the build for the selected platform"
-       @echo "  cscope     Generate cscope index"
+       @echo "  cscope         Generate cscope index"
        @echo "  distclean      Remove all build artifacts for all platforms"
        @echo "  dump           Generate object file dumps"
+       @echo "  fiptool        Build the Firmware Image Package(FIP) creation tool"
        @echo ""
        @echo "note: most build targets require PLAT to be set to a specific platform."
        @echo ""
diff --git a/include/firmware_image_package.h b/include/firmware_image_package.h
new file mode 100644 (file)
index 0000000..ff5e971
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FIRMWARE_IMAGE_PACKAGE_H__
+#define __FIRMWARE_IMAGE_PACKAGE_H__
+
+#include <stdint.h>
+#include <uuid.h>
+
+/* This is used as a signature to validate the blob header */
+#define TOC_HEADER_NAME        0xAA640001
+
+
+/* ToC Entry UUIDs */
+#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \
+       {0x0becf95f, 0x224d, 0x4d3e, 0xa5, 0x44, {0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a} }
+#define UUID_SCP_FIRMWARE_BL30 \
+       {0x3dfd6697, 0xbe89, 0x49e8, 0xae, 0x5d, {0x78, 0xa1, 0x40, 0x60, 0x82, 0x13} }
+#define UUID_EL3_RUNTIME_FIRMWARE_BL31 \
+       {0x6d08d447, 0xfe4c, 0x4698, 0x9b, 0x95, {0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x00} }
+#define UUID_SECURE_PAYLOAD_BL32 \
+       {0x89e1d005, 0xdc53, 0x4713, 0x8d, 0x2b, {0x50, 0x0a, 0x4b, 0x7a, 0x3e, 0x38} }
+#define UUID_NON_TRUSTED_FIRMWARE_BL33 \
+       {0xa7eed0d6, 0xeafc, 0x4bd5, 0x97, 0x82, {0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4} }
+
+typedef struct {
+       uint32_t        name;
+       uint32_t        serial_number;
+       uint64_t        flags;
+} fip_toc_header;
+
+typedef struct {
+       uuid_t          uuid;
+       uint64_t        offset_address;
+       uint64_t        size;
+       uint64_t        flags;
+} fip_toc_entry;
+
+#endif /* __FIRMWARE_IMAGE_PACKAGE_H__ */
diff --git a/include/stdlib/sys/uuid.h b/include/stdlib/sys/uuid.h
new file mode 100644 (file)
index 0000000..5c4767b
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2002 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Portions copyright (c) 2014, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef _SYS_UUID_H_
+#define _SYS_UUID_H_
+
+#include <sys/cdefs.h>
+
+/* Length of a node address (an IEEE 802 address). */
+#define        _UUID_NODE_LEN          6
+
+/*
+ * See also:
+ *      http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
+ *      http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
+ *
+ * A DCE 1.1 compatible source representation of UUIDs.
+ */
+struct uuid {
+       uint32_t        time_low;
+       uint16_t        time_mid;
+       uint16_t        time_hi_and_version;
+       uint8_t         clock_seq_hi_and_reserved;
+       uint8_t         clock_seq_low;
+       uint8_t         node[_UUID_NODE_LEN];
+};
+
+/* XXX namespace pollution? */
+typedef struct uuid uuid_t;
+
+#endif /* _SYS_UUID_H_ */
diff --git a/tools/fip_create/Makefile b/tools/fip_create/Makefile
new file mode 100644 (file)
index 0000000..14e46d3
--- /dev/null
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# Neither the name of ARM nor the names of its contributors may be used
+# to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+PROJECT = fip_create
+OBJECTS = fip_create.o
+
+CFLAGS = -Wall -Werror -pedantic -std=c99
+ifeq ($(BUILD),DEBUG)
+  CFLAGS += -g -O0 -DDEBUG
+else
+  CFLAGS += -O2
+endif
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INCLUDE_PATHS = -I.
+
+CC := gcc
+RM := rm -rf
+
+.PHONY: all clean
+
+all: $(PROJECT)
+
+$(PROJECT): $(OBJECTS) Makefile
+       @echo "[LD] $@"
+       $(CC) $(OBJECTS) -o $@
+
+%.o: %.c %.h Makefile
+       @echo "[CC] $@"
+       $(CC) -c $(CFLAGS) $(INCLUDE_PATHS) $< -o $@
+
+clean:
+       $(RM) $(PROJECT)
+       $(RM) $(OBJECTS)
diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c
new file mode 100644 (file)
index 0000000..d6bfdd9
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <getopt.h> /* getopt_long() is a GNU extention */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "fip_create.h"
+#include "firmware_image_package.h"
+
+file_info files[MAX_FILES];
+unsigned file_info_count = 0;
+uuid_t uuid_null = {0};
+
+/*
+ * TODO: Add ability to specify and flag different file types.
+ * Add flags to the toc_entry?
+ * const char* format_type_str[] = { "RAW", "ELF", "PIC" };
+ */
+
+/* Currently only BL2 and BL31 images are supported. */
+static entry_lookup_list toc_entry_lookup_list[] = {
+       { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+         "bl2", NULL, FLAG_FILENAME },
+       { "SCP Firmware BL3-0", UUID_SCP_FIRMWARE_BL30,
+         "bl30", NULL, FLAG_FILENAME},
+       { "EL3 Runtime Firmware BL3-1", UUID_EL3_RUNTIME_FIRMWARE_BL31,
+         "bl31", NULL, FLAG_FILENAME},
+       { "Secure Payload BL3-2 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32,
+         "bl32", NULL, FLAG_FILENAME},
+       { "Non-Trusted Firmware BL3-3", UUID_NON_TRUSTED_FIRMWARE_BL33,
+         "bl33", NULL, FLAG_FILENAME},
+       { NULL, {0}, 0 }
+};
+
+
+/* Return 0 for equal uuids */
+static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
+{
+       return memcmp(uuid1, uuid2, sizeof(uuid_t));
+}
+
+
+static inline void copy_uuid(uuid_t *to_uuid, const uuid_t *from_uuid)
+{
+       memcpy(to_uuid, from_uuid, sizeof(uuid_t));
+}
+
+
+static void print_usage(void)
+{
+       entry_lookup_list *entry = toc_entry_lookup_list;
+
+       printf("fip_create FIP_FILENAME\n\n");
+       printf("\tThis tool is used to create a Firmware Image Package.\n\n");
+       printf("\t--help: this help\n");
+       printf("\t--dump: print contents of FIP\n\n");
+       printf("\tComponents that can be added/updated:\n");
+       for (; entry->command_line_name != NULL; entry++) {
+               printf("\t  %s:\n\t    --%s ",
+                      entry->name, entry->command_line_name);
+               if (entry->flags & FLAG_FILENAME) {
+                       printf("FILENAME");
+               }
+       printf("\n");
+       }
+}
+
+
+static entry_lookup_list *get_entry_lookup_from_uuid(const uuid_t *uuid)
+{
+       unsigned int lookup_index = 0;
+
+       while (toc_entry_lookup_list[lookup_index].command_line_name != NULL) {
+               if (compare_uuids(&toc_entry_lookup_list[lookup_index].name_uuid,
+                   uuid) == 0) {
+                       return &toc_entry_lookup_list[lookup_index];
+               }
+               lookup_index++;
+       }
+       return NULL;
+}
+
+
+static file_info *find_file_info_from_uuid(const uuid_t *uuid)
+{
+       int index;
+
+       for (index = 0; index < file_info_count; index++) {
+               if (compare_uuids(&files[index].name_uuid, uuid) == 0) {
+                       return &files[index];
+               }
+       }
+       return NULL;
+}
+
+
+static int add_file_info_entry(entry_lookup_list *lookup_entry, char *filename)
+{
+       file_info *file_info_entry;
+       int error;
+       struct stat file_status;
+       bool is_new_entry = false;
+
+       /* Check if the file already exists in the array */
+       file_info_entry = find_file_info_from_uuid(&lookup_entry->name_uuid);
+       if (file_info_entry == NULL) {
+               /* The file does not exist in the current list; take the next
+                * one available in the file_info list. 'file_info_count' is
+                * incremented in case of successful update at the end of the
+                * function.
+                */
+               file_info_entry = &files[file_info_count];
+               is_new_entry = true;
+
+               /* Copy the uuid for the new entry */
+               copy_uuid(&file_info_entry->name_uuid,
+                         &lookup_entry->name_uuid);
+       }
+
+       /* Get the file information for entry */
+       error = stat(filename, &file_status);
+       if (error != 0) {
+               printf("Error: Cannot get information for file \"%s\": %s\n",
+                       filename, strerror(errno));
+               return errno;
+       }
+       file_info_entry->filename = filename;
+       file_info_entry->size = (unsigned int)file_status.st_size;
+       file_info_entry->entry = lookup_entry;
+
+       /* Increment the file_info counter on success if it is new file entry */
+       if (is_new_entry) {
+               file_info_count++;
+
+               /* Ensure we do not overflow */
+               if (file_info_count > MAX_FILES) {
+                       printf("ERROR: Too many files in Package\n");
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+
+static int write_memory_to_file(const uint8_t *start, const char *filename,
+               unsigned int size)
+{
+       FILE *stream;
+       unsigned int bytes_written;
+
+       /* Write the packed file out to the filesystem */
+       stream = fopen(filename, "r+");
+       if (stream == NULL) {
+               stream = fopen(filename, "w");
+               if (stream == NULL) {
+                       printf("Error: Cannot create output file \"%s\": %s\n",
+                              filename, strerror(errno));
+                       return errno;
+               } else {
+                       printf("Creating \"%s\"\n", filename);
+               }
+       } else {
+               printf("Updating \"%s\"\n", filename);
+       }
+
+       bytes_written = fwrite(start, sizeof(uint8_t), size, stream);
+       fclose(stream);
+
+       if (bytes_written != size) {
+               printf("Error: Incorrect write for file \"%s\": Size=%u,"
+                       "Written=%u bytes.\n", filename, size, bytes_written);
+               return EIO;
+       }
+
+       return 0;
+}
+
+
+static int read_file_to_memory(void *memory, const file_info *info)
+{
+       FILE *stream;
+       unsigned int bytes_read;
+
+       /* If the file_info is defined by its filename we need to load it */
+       if (info->filename) {
+               /* Read image from filesystem */
+               stream = fopen(info->filename, "r");
+               if (stream == NULL) {
+                       printf("Error: Cannot open file \"%s\": %s\n",
+                               info->filename, strerror(errno));
+                       return errno;
+               }
+
+               bytes_read = (unsigned int)fread(memory, sizeof(uint8_t),
+                                                info->size, stream);
+               fclose(stream);
+               if (bytes_read != info->size) {
+                       printf("Error: Incomplete read for file \"%s\":"
+                               "Size=%u, Read=%u bytes.\n", info->filename,
+                               info->size, bytes_read);
+                       return EIO;
+               }
+       } else {
+               if (info->image_buffer == NULL) {
+                       printf("ERROR: info->image_buffer = NULL\n");
+                       return EIO;
+               }
+               /* Copy the file_info buffer (extracted from the existing
+                * image package) into the new buffer.
+                */
+               memcpy(memory, info->image_buffer, info->size);
+       }
+
+       return 0;
+}
+
+
+/* Create the image package file */
+static int pack_images(const char *fip_filename)
+{
+       int status;
+       uint8_t *fip_base_address;
+       void *entry_address;
+       fip_toc_header *toc_header;
+       fip_toc_entry *toc_entry;
+       unsigned int entry_index;
+       unsigned int toc_size;
+       unsigned int fip_size;
+       unsigned int entry_offset_address;
+       unsigned int payload_size = 0;
+
+       /* Validate filename */
+       if ((fip_filename == NULL) || (strcmp(fip_filename, "") == 0)) {
+               return EINVAL;
+       }
+
+       /* Payload size calculation */
+       for (entry_index = 0; entry_index < file_info_count; entry_index++) {
+               payload_size += files[entry_index].size;
+       }
+
+       /* Allocate memory for entire package, including the final null entry */
+       toc_size = (sizeof(fip_toc_header) +
+                   (sizeof(fip_toc_entry) * (file_info_count + 1)));
+       fip_size = toc_size + payload_size;
+       fip_base_address = malloc(fip_size);
+       if (fip_base_address == NULL) {
+               printf("Error: Can't allocate enough memory to create package."
+                      "Process aborted.\n");
+               return ENOMEM;
+       }
+       memset(fip_base_address, 0, fip_size);
+
+       /* Create ToC Header */
+       toc_header = (fip_toc_header *)fip_base_address;
+       toc_header->name = TOC_HEADER_NAME;
+       toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
+       toc_header->flags = 0;
+
+       toc_entry = (fip_toc_entry *)(fip_base_address +
+                                     sizeof(fip_toc_header));
+
+       /* Calculate the starting address of the first image, right after the
+        * toc header.
+        */
+       entry_offset_address = toc_size;
+       entry_index = 0;
+
+       /* Create the package in memory. */
+       for (entry_index = 0; entry_index < file_info_count; entry_index++) {
+               entry_address = (fip_base_address + entry_offset_address);
+               status = read_file_to_memory(entry_address,
+                                            &files[entry_index]);
+               if (status != 0) {
+                       printf("Error: While reading \"%s\" from filesystem.\n",
+                               files[entry_index].filename);
+                       return status;
+               }
+
+               copy_uuid(&toc_entry->uuid, &files[entry_index].name_uuid);
+               toc_entry->offset_address = entry_offset_address;
+               toc_entry->size = files[entry_index].size;
+               toc_entry->flags = 0;
+               entry_offset_address += toc_entry->size;
+               toc_entry++;
+       }
+
+       /* Add a null uuid entry to mark the end of toc entries */
+       copy_uuid(&toc_entry->uuid, &uuid_null);
+       toc_entry->offset_address = entry_offset_address;
+       toc_entry->size = 0;
+       toc_entry->flags = 0;
+
+       /* Save the package to file */
+       status = write_memory_to_file(fip_base_address, fip_filename, fip_size);
+       if (status != 0) {
+               printf("Error: Failed while writing package to file \"%s\" "
+                       "with status=%d.\n", fip_filename, status);
+               return status;
+       }
+       return 0;
+}
+
+
+static void dump_toc(void)
+{
+       unsigned int index = 0;
+       unsigned int image_offset;
+       unsigned int image_size = 0;
+
+       image_offset = sizeof(fip_toc_header) +
+               (sizeof(fip_toc_entry) * (file_info_count + 1));
+
+       printf("Firmware Image Package ToC:\n");
+       printf("---------------------------\n");
+       for (index = 0; index < file_info_count; index++) {
+               if (files[index].entry) {
+                       printf("- %s: ", files[index].entry->name);
+               } else {
+                       printf("- Unknown entry: ");
+               }
+               image_size = files[index].size;
+
+               printf("offset=0x%X, size=0x%X\n", image_offset, image_size);
+               image_offset += image_size;
+
+               if (files[index].filename) {
+                       printf("  file: '%s'\n", files[index].filename);
+               }
+       }
+       printf("---------------------------\n");
+}
+
+
+/* Read and load existing package into memory. */
+static int parse_fip(const char *fip_filename)
+{
+       FILE *fip;
+       char *fip_buffer;
+       char *fip_buffer_end;
+       int fip_size, read_fip_size;
+       fip_toc_header *toc_header;
+       fip_toc_entry *toc_entry;
+       bool found_last_toc_entry = false;
+       file_info *file_info_entry;
+       int status = -1;
+       struct stat st;
+
+       fip = fopen(fip_filename, "r");
+       if (fip == NULL) {
+               /* If the fip does not exist just return, it should not be
+                * considered as an error. The package will be created later
+                */
+               status = 0;
+               goto parse_fip_return;
+       }
+
+       if (stat(fip_filename, &st) != 0) {
+               status = errno;
+               goto parse_fip_fclose;
+       } else {
+               fip_size = (int)st.st_size;
+       }
+
+       /* Allocate a buffer to read the package */
+       fip_buffer = (char *)malloc(fip_size);
+       if (fip_buffer == NULL) {
+               printf("ERROR: Cannot allocate %d bytes.\n", fip_size);
+               status = errno;
+               goto parse_fip_fclose;
+       }
+       fip_buffer_end = fip_buffer + fip_size;
+
+       /* Read the file */
+       read_fip_size = fread(fip_buffer, sizeof(char), fip_size, fip);
+       if (read_fip_size != fip_size) {
+               printf("ERROR: Cannot read the FIP.\n");
+               status = EIO;
+               goto parse_fip_free;
+       }
+       fclose(fip);
+       fip = NULL;
+
+       /* The package must at least contain the ToC Header */
+       if (fip_size < sizeof(fip_toc_header)) {
+               printf("ERROR: Given FIP is smaller than the ToC header.\n");
+               status = EINVAL;
+               goto parse_fip_free;
+       }
+       /* Set the ToC Header at the base of the buffer */
+       toc_header = (fip_toc_header *)fip_buffer;
+       /* The first toc entry should be just after the ToC header */
+       toc_entry = (fip_toc_entry *)(toc_header + 1);
+
+       /* While the ToC entry is contained into the buffer */
+       int cnt = 0;
+       while (((char *)toc_entry + sizeof(fip_toc_entry)) < fip_buffer_end) {
+               cnt++;
+               /* Check if the ToC Entry is the last one */
+               if (compare_uuids(&toc_entry->uuid, &uuid_null) == 0) {
+                       found_last_toc_entry = true;
+                       status = 0;
+                       break;
+               }
+
+               /* Add the entry into file_info */
+
+               /* Get the new entry in the array and clear it */
+               file_info_entry = &files[file_info_count++];
+               memset(file_info_entry, 0, sizeof(file_info));
+
+               /* Copy the info from the ToC entry */
+               copy_uuid(&file_info_entry->name_uuid, &toc_entry->uuid);
+               file_info_entry->image_buffer = fip_buffer +
+                 toc_entry->offset_address;
+               file_info_entry->size = toc_entry->size;
+
+               /* Check if there is a corresponding entry in lookup table */
+               file_info_entry->entry =
+                 get_entry_lookup_from_uuid(&toc_entry->uuid);
+
+               /* Go to the next ToC entry */
+               toc_entry++;
+       }
+
+       if (!found_last_toc_entry) {
+               printf("ERROR: Given FIP does not have an end ToC entry.\n");
+               status = EINVAL;
+               goto parse_fip_free;
+       } else {
+               /* All is well, we should not free any of the loaded images */
+               goto parse_fip_fclose;
+       }
+
+ parse_fip_free:
+       if (fip_buffer != NULL) {
+               free(fip_buffer);
+               fip_buffer = NULL;
+       }
+
+ parse_fip_fclose:
+       if (fip != NULL) {
+               fclose(fip);
+       }
+
+ parse_fip_return:
+       return status;
+}
+
+
+/* Parse all command-line options and return the FIP name if present. */
+static char *get_filename(int argc, char **argv, struct option *options)
+{
+       int c;
+       char *filename = NULL;
+
+       /* Reset option pointer so we parse all args. starts at 1.
+        * The filename is the only argument that does not have an option flag.
+        */
+       optind = 1;
+       while (1) {
+               c = getopt_long(argc, argv, "", options, NULL);
+               if (c == -1)
+                       break;
+
+               if (c == '?') {
+                       /* Failed to parse an option. Fail. */
+                       return NULL;
+               }
+       }
+
+       /* Only one argument left then it is the filename.
+        * We dont expect any other options
+        */
+       if (optind + 1 == argc) {
+               filename = argv[optind];
+       } else {
+               printf("ERROR: Too many arguments.\n");
+       }
+
+       return filename;
+}
+
+
+/* Work through command-line options */
+static int parse_cmdline(int argc, char **argv, struct option *options,
+                        int *do_pack)
+{
+       int c;
+       int status = 0;
+       int option_index = 0;
+       entry_lookup_list *lookup_entry;
+       int do_dump = 0;
+
+       /* restart parse to process all options. starts at 1. */
+       optind = 1;
+       while (1) {
+               c = getopt_long(argc, argv, "", options, &option_index);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 0:
+                       /* if this is --dump, set action and continue */
+                       if (strcmp(options[option_index].name, "dump") == 0) {
+                               do_dump = 1;
+                               continue;
+                       }
+
+                       if (optarg) {
+                               /* Does the option expect a filename. */
+                               lookup_entry = &toc_entry_lookup_list[option_index];
+                               if (lookup_entry->flags & FLAG_FILENAME) {
+                                       status = add_file_info_entry(lookup_entry, optarg);
+                                       if (status != 0) {
+                                               printf("Failed to process %s\n",
+                                                      options[option_index].name);
+                                               break;
+                                       } else {
+                                               /* Update package */
+                                               *do_pack = 1;
+                                       }
+                               }
+                       }
+                       break;
+               default:
+                       /* Unrecognised options are caught in get_filename() */
+                       break;
+               }
+       }
+
+
+       /* Do not dump toc if we have an error as it could hide the error */
+       if ((status == 0) && (do_dump)) {
+               dump_toc();
+       }
+
+       return status;
+
+}
+
+int main(int argc, char **argv)
+{
+       int i;
+       int status;
+       char *fip_filename;
+       int do_pack = 0;
+
+       /* Clear file list table. */
+       memset(files, 0, sizeof(files));
+
+       /* Initialise for getopt_long().
+        * Use image table as defined at top of file to get options.
+        * Add 'dump' option and end marker.
+        */
+       static struct option long_options[(sizeof(toc_entry_lookup_list)/
+                                          sizeof(entry_lookup_list)) + 1];
+
+       for (i = 0;
+            /* -1 because we dont want to process end marker in toc table */
+            i < sizeof(toc_entry_lookup_list)/sizeof(entry_lookup_list) - 1;
+            i++) {
+               long_options[i].name = toc_entry_lookup_list[i].command_line_name;
+               /* The only flag defined at the moment is for a FILENAME */
+               long_options[i].has_arg = toc_entry_lookup_list[i].flags ? 1 : 0;
+               long_options[i].flag = 0;
+               long_options[i].val = 0;
+       }
+
+       /* Add '--dump' option */
+       long_options[i].name = "dump";
+       long_options[i].has_arg = 0;
+       long_options[i].flag = 0;
+       long_options[i].val = 0;
+
+       /* Zero the last entry (required) */
+       long_options[++i].name = 0;
+       long_options[i].has_arg = 0;
+       long_options[i].flag = 0;
+       long_options[i].val = 0;
+
+#ifdef DEBUG
+       /* Print all supported options */
+       for (i = 0; i < sizeof(long_options)/sizeof(struct option); i++) {
+               printf("long opt (%d) : name = %s\n", i, long_options[i].name);
+       }
+#endif /* DEBUG */
+
+       /* As the package may already exist and is to be updated we need to get
+        * the filename from the arguments and load from it.
+        * NOTE: As this is the first function to look at the program arguments
+        * it causes a failure if bad options were provided.
+        */
+       fip_filename = get_filename(argc, argv, long_options);
+       if (fip_filename == NULL) {
+               print_usage();
+               return 0;
+       }
+
+       /* Try to open the file and load it into memory */
+       status = parse_fip(fip_filename);
+       if (status != 0) {
+               return status;
+       }
+
+       /* Work through provided program arguments and perform actions */
+       status = parse_cmdline(argc, argv, long_options, &do_pack);
+       if (status != 0) {
+               return status;
+       };
+
+       /* Processed all command line options. Create/update the package if
+        * required.
+        */
+       if (do_pack) {
+               status = pack_images(fip_filename);
+               if (status != 0) {
+                       printf("Failed to create package (status = %d).\n",
+                              status);
+               }
+       }
+
+       return status;
+}
diff --git a/tools/fip_create/fip_create.h b/tools/fip_create/fip_create.h
new file mode 100644 (file)
index 0000000..f2e022f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FIP_CREATE_H__
+#define __FIP_CREATE_H__
+
+#include <stdint.h>
+#include <uuid.h>
+
+#define MAX_FILES                      10
+
+/* TODO: Update this number as required */
+#define TOC_HEADER_SERIAL_NUMBER       0x12345678
+
+#define FLAG_FILENAME                  (1 << 0)
+
+typedef struct {
+       const char              *name;
+       uuid_t                   name_uuid;
+       const char              *command_line_name;
+       struct file_info        *info;
+       unsigned int             flags;
+} entry_lookup_list;
+
+typedef struct {
+       uuid_t                   name_uuid;
+       const char              *filename;
+       unsigned int             size;
+       void                    *image_buffer;
+       entry_lookup_list       *entry;
+} file_info;
+
+#endif /* __FIP_CREATE_H__ */
diff --git a/tools/fip_create/firmware_image_package.h b/tools/fip_create/firmware_image_package.h
new file mode 120000 (symlink)
index 0000000..2c0d017
--- /dev/null
@@ -0,0 +1 @@
+../../include/firmware_image_package.h
\ No newline at end of file
diff --git a/tools/fip_create/uuid.h b/tools/fip_create/uuid.h
new file mode 120000 (symlink)
index 0000000..c77762f
--- /dev/null
@@ -0,0 +1 @@
+../../include/stdlib/sys/uuid.h
\ No newline at end of file