diff --git a/.gitignore b/.gitignore index 7447227..d2cff7c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,13 +10,14 @@ # Ignore build products from tools tools/**/*.o -tools/fip_create/fip_create -tools/fip_create/fip_create.exe +tools/fip_create/ +tools/fiptool/fiptool +tools/fiptool/fiptool.exe tools/cert_create/src/*.o tools/cert_create/src/**/*.o tools/cert_create/cert_create tools/cert_create/cert_create.exe # Ignore header files copied. -tools/fip_create/firmware_image_package.h -tools/fip_create/uuid.h +tools/fiptool/firmware_image_package.h +tools/fiptool/uuid.h diff --git a/Makefile b/Makefile index 5f4a93c..bbda656 100644 --- a/Makefile +++ b/Makefile @@ -382,7 +382,7 @@ endif ################################################################################ -# Auxiliary tools (fip_create, cert_create, etc) +# Auxiliary tools (fiptool, cert_create, etc) ################################################################################ # Variables for use with Certificate Generation Tool @@ -390,8 +390,8 @@ CRTTOOL ?= ${CRTTOOLPATH}/cert_create${BIN_EXT} # Variables for use with Firmware Image Package -FIPTOOLPATH ?= tools/fip_create -FIPTOOL ?= ${FIPTOOLPATH}/fip_create${BIN_EXT} +FIPTOOLPATH ?= tools/fiptool +FIPTOOL ?= ${FIPTOOLPATH}/fiptool${BIN_EXT} ################################################################################ @@ -603,7 +603,8 @@ endif ${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} ${FIPTOOL} - ${Q}${FIPTOOL} --dump ${FIP_ARGS} $@ + ${Q}${FIPTOOL} create ${FIP_ARGS} $@ + ${Q}${FIPTOOL} info $@ @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} @@ -618,7 +619,8 @@ endif ${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS} ${FIPTOOL} - ${Q}${FIPTOOL} --dump ${FWU_FIP_ARGS} $@ + ${Q}${FIPTOOL} create ${FWU_FIP_ARGS} $@ + ${Q}${FIPTOOL} info $@ @echo @echo "Built $@ successfully" @echo @@ -629,7 +631,7 @@ .PHONY: ${FIPTOOL} ${FIPTOOL}: - ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} + ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${FIPTOOLPATH} cscope: @echo " CSCOPE" diff --git a/docs/firmware-design.md b/docs/firmware-design.md index 294349d..74ea5eb 100644 --- a/docs/firmware-design.md +++ b/docs/firmware-design.md @@ -1511,11 +1511,16 @@ ARM Trusted firmware. The ToC header has the following fields: + `name`: The name of the ToC. This is currently used to validate the header. `serial_number`: A non-zero number provided by the creation tool - `flags`: Flags associated with this data. None are yet defined. + `flags`: Flags associated with this data. + Bits 0-13: Reserved + Bits 32-47: Platform defined + Bits 48-63: Reserved A ToC entry has the following fields: + `uuid`: All files are referred to by a pre-defined Universally Unique IDentifier [UUID] . The UUIDs are defined in `include/firmware_image_package`. The platform translates the requested @@ -1532,7 +1537,7 @@ currently only supports packing bootloader images. Additional image definitions can be added to the tool as required. -The tool can be found in `tools/fip_create`. +The tool can be found in `tools/fiptool`. ### Loading from a Firmware Image Package (FIP) diff --git a/docs/trusted-board-boot.md b/docs/trusted-board-boot.md index f076cd3..833b5db 100644 --- a/docs/trusted-board-boot.md +++ b/docs/trusted-board-boot.md @@ -229,7 +229,7 @@ images and keys as inputs (keys must be in PEM format) and generates the certificates (in DER format) required to establish the CoT. New keys can be generated by the tool in case they are not provided. The certificates are then -passed as inputs to the `fip_create` tool for creating the FIP. +passed as inputs to the `fiptool` utility for creating the FIP. The certificates are also stored individually in the in the output build directory. diff --git a/docs/user-guide.md b/docs/user-guide.md index 41a272f..0f3c999 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -269,7 +269,7 @@ * `GENERATE_COT`: Boolean flag used to build and execute the `cert_create` tool to create certificates as per the Chain of Trust described in - [Trusted Board Boot]. The build system then calls the `fip_create` tool to + [Trusted Board Boot]. The build system then calls `fiptool` to include the certificates in the FIP and FWU_FIP. Default value is '0'. Specify both `TRUSTED_BOARD_BOOT=1` and `GENERATE_COT=1` to include support @@ -628,7 +628,7 @@ It is recommended to remove old artifacts before building the tool: - make -C tools/fip_create clean + make -C tools/fiptool clean Build the tool: @@ -636,37 +636,58 @@ The tool binary can be located in: - ./tools/fip_create/fip_create + ./tools/fiptool/fiptool Invoking the tool with `--help` will print a help message with all available options. Example 1: create a new Firmware package `fip.bin` that contains BL2 and BL31: - ./tools/fip_create/fip_create \ + ./tools/fiptool/fiptool create \ --tb-fw build///bl2.bin \ --soc-fw build///bl31.bin \ fip.bin Example 2: view the contents of an existing Firmware package: - ./tools/fip_create/fip_create --dump /fip.bin + ./tools/fiptool/fiptool info /fip.bin Example 3: update the entries of an existing Firmware package: # Change the BL2 from Debug to Release version - ./tools/fip_create/fip_create \ + ./tools/fiptool/fiptool update \ --tb-fw build//release/bl2.bin \ build//debug/fip.bin Example 4: unpack all entries from an existing Firmware package: # Images will be unpacked to the working directory - ./tools/fip_create/fip_create --unpack /fip.bin + ./tools/fiptool/fiptool unpack /fip.bin + +Example 5: remove an entry from an existing Firmware package: + + ./tools/fiptool/fiptool remove \ + --tb-fw build//debug/fip.bin + +Note that if the destination FIP file exists, the create, update and +remove operations will automatically overwrite it. + +The unpack operation will fail if the images already exist at the +destination. In that case, use -f or --force to continue. More information about FIP can be found in the [Firmware Design document] [Firmware Design]. +#### Migrating from fip_create to fiptool + +The previous version of fiptool was called fip_create. A compatibility script +that emulates the basic functionality of the previous fip_create is provided. +However, users are strongly encouraged to migrate to fiptool. + +* To create a new FIP file, replace "fip_create" with "fiptool create". +* To update a FIP file, replace "fip_create" with "fiptool update". +* To dump the contents of a FIP file, replace "fip_create --dump" + with "fiptool info". ### Building FIP images with support for Trusted Board Boot @@ -798,21 +819,21 @@ 2. Obtain SCP_BL2 (Juno) and BL33 (all platforms) - Use the fip_create tool to extract the SCP_BL2 and BL33 images from the FIP + Use the fiptool to extract the SCP_BL2 and BL33 images from the FIP package included in the Linaro release: - # Build the fip_create tool + # Build the fiptool make [DEBUG=1] [V=1] fiptool # Unpack firmware images from Linaro FIP - ./tools/fip_create/fip_create --unpack \ + ./tools/fiptool/fiptool unpack \ /fip.bin The unpack operation will result in a set of binary images extracted to the working directory. The SCP_BL2 image corresponds to `scp-fw.bin` and BL33 corresponds to `nt-fw.bin`. - Note: the fip_create tool will complain if the images to be unpacked already + Note: the fiptool will complain if the images to be unpacked already exist in the current directory. If that is the case, either delete those files or use the `--force` option to overwrite. diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk index 165e3aa..16bdd78 100644 --- a/make_helpers/build_macros.mk +++ b/make_helpers/build_macros.mk @@ -112,7 +112,7 @@ ${BUILD_PLAT}/bl$(1).bin endef -# FIP_ADD_PAYLOAD appends the command line arguments required by the FIP tool +# FIP_ADD_PAYLOAD appends the command line arguments required by fiptool # to package a new payload. Optionally, it adds the dependency on this payload # $(1) = payload filename (i.e. bl31.bin) # $(2) = command line option for the specified payload (i.e. --bl31) @@ -135,7 +135,7 @@ # using a build option. It also adds a dependency on the image file, aborting # the build if the file does not exist. # $(1) = build option to specify the image filename (SCP_BL2, BL33, etc) -# $(2) = command line option for the fip_create tool (scp_bl2, bl33, etc) +# $(2) = command line option for fiptool (scp_bl2, bl33, etc) # Example: # $(eval $(call FIP_ADD_IMG,BL33,--bl33)) define FIP_ADD_IMG @@ -147,7 +147,7 @@ $$(if $(value $(1)),,$$(error "Platform '${PLAT}' requires $(1). Please set $(1) to point to the right file")) endef -# FWU_FIP_ADD_PAYLOAD appends the command line arguments required by the FIP tool +# FWU_FIP_ADD_PAYLOAD appends the command line arguments required by fiptool # to package a new FWU payload. Optionally, it adds the dependency on this payload # $(1) = payload filename (e.g. ns_bl2u.bin) # $(2) = command line option for the specified payload (e.g. --fwu) @@ -168,7 +168,7 @@ # FWU_FIP_ADD_IMG allows the platform to pack a binary image in the FWU FIP # $(1) build option to specify the image filename (BL2U, NS_BL2U, etc) -# $(2) command line option for the fip_create tool (bl2u, ns_bl2u, etc) +# $(2) command line option for fiptool (bl2u, ns_bl2u, etc) # Example: # $(eval $(call FWU_FIP_ADD_IMG,BL2U,--bl2u)) define FWU_FIP_ADD_IMG @@ -301,7 +301,7 @@ endef -# MAKE_TOOL_ARGS macro defines the command line arguments for the FIP tool for +# MAKE_TOOL_ARGS macro defines the command line arguments for fiptool for # each BL image. Arguments: # $(1) = BL stage (2, 30, 31, 32, 33) # $(2) = Binary file diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk index 71d9747..8d3f14f 100644 --- a/make_helpers/tbbr/tbbr_tools.mk +++ b/make_helpers/tbbr/tbbr_tools.mk @@ -30,7 +30,7 @@ # This file defines the keys and certificates that must be created to establish # a Chain of Trust following the TBBR document. These definitions include the -# command line options passed to the cert_create and fip_create tools. +# command line options passed to the cert_create and fiptool commands. # # Expected environment: # @@ -66,11 +66,11 @@ $(eval $(call CERT_ADD_CMD_OPT,${TFW_NVCTR_VAL},--tfw-nvctr)) $(eval $(call CERT_ADD_CMD_OPT,${NTFW_NVCTR_VAL},--ntfw-nvctr)) -# Add Trusted Key certificate to the fip_create and cert_create command line options +# Add Trusted Key certificate to the fiptool and cert_create command line options $(eval $(call FIP_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert)) $(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_KEY_CERT},--trusted-key-cert)) -# Add fwu certificate to the fip_create and cert_create command line options +# Add fwu certificate to the fiptool and cert_create command line options $(eval $(call FWU_FIP_ADD_PAYLOAD,${FWU_CERT},--fwu-cert)) $(eval $(call FWU_CERT_ADD_CMD_OPT,${FWU_CERT},--fwu-cert)) diff --git a/tools/fip_create/Makefile b/tools/fip_create/Makefile deleted file mode 100644 index 30e4b82..0000000 --- a/tools/fip_create/Makefile +++ /dev/null @@ -1,83 +0,0 @@ -# -# Copyright (c) 2014-2016, 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. -# - -MAKE_HELPERS_DIRECTORY := ../../make_helpers/ -include ${MAKE_HELPERS_DIRECTORY}build_macros.mk -include ${MAKE_HELPERS_DIRECTORY}build_env.mk - -PROJECT := fip_create${BIN_EXT} -OBJECTS := fip_create.o -COPIED_H_FILES := uuid.h firmware_image_package.h - -CFLAGS := -Wall -Werror -pedantic -std=c99 -ifeq (${DEBUG},1) - CFLAGS += -g -O0 -DDEBUG -else - CFLAGS += -O2 -endif - -# Only include from local directory (see comment below). -INCLUDE_PATHS := -I. - -CC := gcc - -.PHONY: all clean distclean - -all: ${PROJECT} - -${PROJECT}: ${OBJECTS} Makefile - @echo " LD $@" - ${Q}${CC} ${OBJECTS} -o $@ - @${ECHO_BLANK_LINE} - @echo "Built $@ successfully" - @${ECHO_BLANK_LINE} - -%.o: %.c %.h ${COPIED_H_FILES} Makefile - @echo " CC $<" - ${Q}${CC} -c ${CFLAGS} ${INCLUDE_PATHS} $< -o $@ - -# -# Copy required library headers to a local directory so they can be included -# by this project without adding the library directories to the system include -# path. This avoids conflicts with definitions in the compiler standard -# include path. -# -uuid.h : ../../include/lib/stdlib/sys/uuid.h - $(call SHELL_COPY,$<,$@) - -firmware_image_package.h : ../../include/common/firmware_image_package.h - $(call SHELL_COPY,$<,$@) - -clean: - $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) - -distclean: clean - $(call SHELL_DELETE_ALL, ${COPIED_H_FILES}) - diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c deleted file mode 100644 index 48cb3f6..0000000 --- a/tools/fip_create/fip_create.c +++ /dev/null @@ -1,852 +0,0 @@ -/* - * Copyright (c) 2014-2016, 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 -#include /* getopt_long() is a GNU extention */ -#include -#include -#include -#include -#include -#include "fip_create.h" -#include "firmware_image_package.h" - -/* Values returned by getopt() as part of the command line parsing */ -#define OPT_TOC_ENTRY 0 -#define OPT_DUMP 'd' -#define OPT_HELP 'h' -#define OPT_UNPACK 'u' -#define OPT_FORCE 'f' -#define OPT_STR "dfhu" - -static file_info_t files[MAX_FILES]; -static unsigned file_info_count; -static uuid_t uuid_null = {0}; -static int do_dump; -static int do_pack; -static int do_unpack; -static int do_force; - -/* - * TODO: Add ability to specify and flag different file types. - * Add flags to the toc_entry? - * const char* format_type_str[] = { "RAW", "ELF", "PIC" }; - */ - -/* The images used depends on the platform. */ -static entry_lookup_list_t toc_entry_lookup_list[] = { - { "SCP Firmware Updater Configuration FWU SCP_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U, - "scp-fwu-cfg", NULL, FLAG_FILENAME }, - { "AP Firmware Updater Configuration BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U, - "ap-fwu-cfg", NULL, FLAG_FILENAME }, - { "Firmware Updater NS_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U, - "fwu", NULL, FLAG_FILENAME }, - { "Non-Trusted Firmware Updater certificate", UUID_TRUSTED_FWU_CERT, - "fwu-cert", NULL, FLAG_FILENAME}, - { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2, - "tb-fw", NULL, FLAG_FILENAME }, - { "SCP Firmware SCP_BL2", UUID_SCP_FIRMWARE_SCP_BL2, - "scp-fw", NULL, FLAG_FILENAME}, - { "EL3 Runtime Firmware BL31", UUID_EL3_RUNTIME_FIRMWARE_BL31, - "soc-fw", NULL, FLAG_FILENAME}, - { "Secure Payload BL32 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32, - "tos-fw", NULL, FLAG_FILENAME}, - { "Non-Trusted Firmware BL33", UUID_NON_TRUSTED_FIRMWARE_BL33, - "nt-fw", NULL, FLAG_FILENAME}, - /* Key Certificates */ - { "Root Of Trust key certificate", UUID_ROT_KEY_CERT, - "rot-cert", NULL, FLAG_FILENAME }, - { "Trusted key certificate", UUID_TRUSTED_KEY_CERT, - "trusted-key-cert", NULL, FLAG_FILENAME}, - { "SCP Firmware key certificate", UUID_SCP_FW_KEY_CERT, - "scp-fw-key-cert", NULL, FLAG_FILENAME}, - { "SoC Firmware key certificate", UUID_SOC_FW_KEY_CERT, - "soc-fw-key-cert", NULL, FLAG_FILENAME}, - { "Trusted OS Firmware key certificate", UUID_TRUSTED_OS_FW_KEY_CERT, - "tos-fw-key-cert", NULL, FLAG_FILENAME}, - { "Non-Trusted Firmware key certificate", UUID_NON_TRUSTED_FW_KEY_CERT, - "nt-fw-key-cert", NULL, FLAG_FILENAME}, - /* Content certificates */ - { "Trusted Boot Firmware BL2 certificate", UUID_TRUSTED_BOOT_FW_CERT, - "tb-fw-cert", NULL, FLAG_FILENAME }, - { "SCP Firmware content certificate", UUID_SCP_FW_CONTENT_CERT, - "scp-fw-cert", NULL, FLAG_FILENAME}, - { "SoC Firmware content certificate", UUID_SOC_FW_CONTENT_CERT, - "soc-fw-cert", NULL, FLAG_FILENAME}, - { "Trusted OS Firmware content certificate", UUID_TRUSTED_OS_FW_CONTENT_CERT, - "tos-fw-cert", NULL, FLAG_FILENAME}, - { "Non-Trusted Firmware content certificate", UUID_NON_TRUSTED_FW_CONTENT_CERT, - "nt-fw-cert", 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_t *entry = toc_entry_lookup_list; - - printf("\nThis tool is used to create a Firmware Image Package.\n\n"); - printf("Usage:\n"); - printf("\tfip_create [options] FIP_FILENAME\n\n"); - printf("Options:\n"); - printf("\t-h,--help: Print this help message and exit\n"); - printf("\t-d,--dump: Print contents of FIP after update\n"); - printf("\t-u,--unpack: Unpack images from an existing FIP\n"); - printf("\t-f,--force: Overwrite existing files when unpacking images\n\n"); - printf("Components that can be added/updated:\n"); - for (; entry->command_line_name != NULL; entry++) { - printf("\t--%s%s\t\t%s", - entry->command_line_name, - (entry->flags & FLAG_FILENAME) ? " FILENAME" : "", - entry->name); - printf("\n"); - } - printf("\n"); -} - - -static entry_lookup_list_t *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_t *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_t *lookup_entry, char *filename) -{ - file_info_t *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_t *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_t *toc_header; - fip_toc_entry_t *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_t) + - (sizeof(fip_toc_entry_t) * (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_t *)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_t *)(fip_base_address + - sizeof(fip_toc_header_t)); - - /* 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; -} - - -/* - * Unpack all images from an existing FIP - * - * Images will be unpacked into the working directory using filenames as - * specified by the corresponding command line option plus the 'bin' extension. - * For example, the image specified by the --soc-fw option will be unpacked as - * 'soc-fw.bin' - */ -static int unpack_images(void) -{ - FILE *stream; - size_t bytes_written; - file_info_t *file_info; - char *filename[MAX_FILES]; - int status, ret = 0; - unsigned int i, idx, num_img; - struct stat st; - size_t len; - - /* Make the output filenames */ - for (idx = 0; idx < file_info_count; idx++) { - filename[idx] = NULL; - file_info = &files[idx]; - if (file_info->image_buffer == NULL) { - continue; - } - len = strlen(file_info->entry->command_line_name); - filename[idx] = malloc(len + 5); /* ".bin" + '\0' */ - if (filename[idx] == NULL) { - printf("ERROR: out of memory\n"); - for (i = 0; i < idx; i++) { - free(filename[i]); - } - return ENOMEM; - } - strcpy(filename[idx], file_info->entry->command_line_name); - strcat(filename[idx], ".bin"); - } - - - /* Check if output files already exist in the filesystem. We perform - * this check before any other action, so if any of the files - * exists, nothing is unpacked. If force overwrite is enabled, we skip - * this check */ - if (!do_force) { - for (idx = 0; idx < file_info_count; idx++) { - file_info = &files[idx]; - if (file_info->image_buffer == NULL) { - continue; - } - status = stat(filename[idx], &st); - if (!status) { - printf("File '%s' exists. Use --force to overwrite.\n", - filename[idx]); - printf("Process aborted.\n"); - ret = EEXIST; - goto unpack_images_free; - } - } - } - - printf("Unpacking images...\n"); - - /* Write the images to files */ - num_img = 0; - for (idx = 0; idx < file_info_count; idx++) { - file_info = &files[idx]; - if (file_info->image_buffer == NULL) { - continue; - } - /* Unpack the image to a file */ - stream = fopen(filename[idx], "w"); - if (!stream) { - printf("ERROR: cannot open '%s' for writing\n", - filename[idx]); - ret = EIO; - goto unpack_images_free; - } - bytes_written = fwrite(file_info->image_buffer, sizeof(uint8_t), - file_info->size, stream); - fclose(stream); - - if (bytes_written != file_info->size) { - printf("ERROR: Incorrect write for file \"%s\": Size=%u," - "Written=%lu bytes.\n", filename[idx], file_info->size, - bytes_written); - ret = EIO; - goto unpack_images_free; - } - num_img++; - } - - printf("Done. %u images unpacked\n", num_img); - -unpack_images_free: - for (idx = 0; idx < file_info_count; idx++) { - free(filename[idx]); - } - - return ret; -} - - -static void dump_toc(void) -{ - unsigned int index = 0; - unsigned int image_offset; - unsigned int image_size = 0; - - image_offset = sizeof(fip_toc_header_t) + - (sizeof(fip_toc_entry_t) * (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_t *toc_header; - fip_toc_entry_t *toc_entry; - bool found_last_toc_entry = false; - file_info_t *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_t)) { - 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_t *)fip_buffer; - /* The first toc entry should be just after the ToC header */ - toc_entry = (fip_toc_entry_t *)(toc_header + 1); - - /* While the ToC entry is contained into the buffer */ - int cnt = 0; - while (((char *)toc_entry + sizeof(fip_toc_entry_t)) < 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_t)); - - /* 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, OPT_STR, 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]; - - return filename; -} - - -/* Work through command-line options */ -static int parse_cmdline(int argc, char **argv, struct option *options) -{ - int c; - int status = 0; - int option_index = 0; - entry_lookup_list_t *lookup_entry; - - /* restart parse to process all options. starts at 1. */ - optind = 1; - while (1) { - c = getopt_long(argc, argv, OPT_STR, options, &option_index); - if (c == -1) - break; - - switch (c) { - case OPT_TOC_ENTRY: - 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); - return status; - } else { - /* Update package */ - do_pack = 1; - } - } - } - break; - - case OPT_DUMP: - do_dump = 1; - break; - - case OPT_HELP: - print_usage(); - exit(0); - - case OPT_UNPACK: - do_unpack = 1; - break; - - case OPT_FORCE: - do_force = 1; - break; - - default: - /* Unrecognised options are caught in get_filename() */ - break; - } - } - - return status; - -} - -int main(int argc, char **argv) -{ - int i; - int status; - char *fip_filename; - struct stat st; - - /* 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 common options and end marker. - */ - static struct option long_options[(sizeof(toc_entry_lookup_list)/ - sizeof(entry_lookup_list_t)) + 4]; - - 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_t) - 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 = OPT_TOC_ENTRY; - } - - /* Add '--dump' option */ - long_options[i].name = "dump"; - long_options[i].has_arg = 0; - long_options[i].flag = 0; - long_options[i].val = OPT_DUMP; - - /* Add '--help' option */ - long_options[++i].name = "help"; - long_options[i].has_arg = 0; - long_options[i].flag = 0; - long_options[i].val = OPT_HELP; - - /* Add '--unpack' option */ - long_options[++i].name = "unpack"; - long_options[i].has_arg = 0; - long_options[i].flag = 0; - long_options[i].val = OPT_UNPACK; - - /* Add '--force' option */ - long_options[++i].name = "force"; - long_options[i].has_arg = 0; - long_options[i].flag = 0; - long_options[i].val = OPT_FORCE; - - /* 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); - - /* Try to open the file and load it into memory */ - if (fip_filename != NULL) { - 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); - if (status != 0) { - return status; - }; - - if (fip_filename == NULL) { - printf("ERROR: Missing FIP filename\n"); - print_usage(); - return EINVAL; - } - - /* Unpack images from FIP always takes precedence over packaging. In - * the future, there will be different commands for each action and - * only one will be specified in the command line */ - if (do_unpack) { - status = stat(fip_filename, &st); - if (status != 0) { - printf("ERROR: cannot open %s\n", fip_filename); - return status; - } - /* Warning if user has specified images */ - if (do_pack) { - printf("WARNING: Unpack option specified. Input images " - "will be ignored.\n"); - } - status = unpack_images(); - if (status != 0) { - printf("ERROR: failed to unpack package (status = %d).\n", - status); - return status; - } - } else if (do_pack) { - /* Create/update FIP */ - status = pack_images(fip_filename); - if (status != 0) { - printf("Failed to create package (status = %d).\n", - status); - } - } - - /* Do not dump toc if we have an error as it could hide the error */ - if ((status == 0) && (do_dump)) { - dump_toc(); - } - - return status; -} diff --git a/tools/fip_create/fip_create.h b/tools/fip_create/fip_create.h deleted file mode 100644 index 3258335..0000000 --- a/tools/fip_create/fip_create.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 -#include - -#define MAX_FILES 20 - -/* TODO: Update this number as required */ -#define TOC_HEADER_SERIAL_NUMBER 0x12345678 - -#define FLAG_FILENAME (1 << 0) - -typedef struct entry_lookup_list { - const char *name; - uuid_t name_uuid; - const char *command_line_name; - struct file_info *info; - unsigned int flags; -} entry_lookup_list_t; - -typedef struct file_info { - uuid_t name_uuid; - const char *filename; - unsigned int size; - void *image_buffer; - entry_lookup_list_t *entry; -} file_info_t; - -#endif /* __FIP_CREATE_H__ */ diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile new file mode 100644 index 0000000..ec9dd99 --- /dev/null +++ b/tools/fiptool/Makefile @@ -0,0 +1,94 @@ +# +# Copyright (c) 2014-2016, 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. +# + +MAKE_HELPERS_DIRECTORY := ../../make_helpers/ +include ${MAKE_HELPERS_DIRECTORY}build_macros.mk +include ${MAKE_HELPERS_DIRECTORY}build_env.mk + +PROJECT := fiptool${BIN_EXT} +OBJECTS := fiptool.o tbbr_config.o +V := 0 +COPIED_H_FILES := uuid.h firmware_image_package.h + +override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700 +CFLAGS := -Wall -Werror -pedantic -std=c99 +ifeq (${DEBUG},1) + CFLAGS += -g -O0 -DDEBUG +else + CFLAGS += -O2 +endif + +ifeq (${V},0) + Q := @ +else + Q := +endif + +# Only include from local directory (see comment below). +INCLUDE_PATHS := -I. + +CC := gcc + +.PHONY: all clean distclean + +all: ${PROJECT} fip_create + +${PROJECT}: ${OBJECTS} Makefile + @echo " LD $@" + ${Q}${CC} ${OBJECTS} -o $@ + @${ECHO_BLANK_LINE} + @echo "Built $@ successfully" + @${ECHO_BLANK_LINE} + +fip_create: fip_create.sh + mkdir -p ../fip_create + install -m 755 fip_create.sh ../fip_create/fip_create + +%.o: %.c %.h ${COPIED_H_FILES} Makefile + @echo " CC $<" + ${Q}${CC} -c ${CPPFLAGS} ${CFLAGS} ${INCLUDE_PATHS} $< -o $@ + +# +# Copy required library headers to a local directory so they can be included +# by this project without adding the library directories to the system include +# path. This avoids conflicts with definitions in the compiler standard +# include path. +# +uuid.h : ../../include/lib/stdlib/sys/uuid.h + $(call SHELL_COPY,$<,$@) + +firmware_image_package.h : ../../include/common/firmware_image_package.h + $(call SHELL_COPY,$<,$@) + +clean: + $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS} fip_create) + +distclean: clean + $(call SHELL_DELETE_ALL, ${COPIED_H_FILES}) diff --git a/tools/fiptool/fip_create.sh b/tools/fiptool/fip_create.sh new file mode 100644 index 0000000..207f238 --- /dev/null +++ b/tools/fiptool/fip_create.sh @@ -0,0 +1,148 @@ +#!/bin/sh +# +# Copyright (c) 2016, 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. +# +# This script implements the old fip_create tool on top of +# the new fiptool. + +usage() { + cat << EOF +This tool is used to create a Firmware Image Package. + +Usage: + fip_create [options] FIP_FILENAME + +Options: + -h,--help: Print this help message and exit + -d,--dump: Print contents of FIP after update + -u,--unpack: Unpack images from an existing FIP + -f,--force: Overwrite existing files when unpacking images + +Components that can be added/updated: + --scp-fwu-cfg FILENAME SCP Firmware Updater Configuration FWU SCP_BL2U + --ap-fwu-cfg FILENAME AP Firmware Updater Configuration BL2U + --fwu FILENAME Firmware Updater NS_BL2U + --fwu-cert FILENAME Non-Trusted Firmware Updater certificate + --tb-fw FILENAME Trusted Boot Firmware BL2 + --scp-fw FILENAME SCP Firmware SCP_BL2 + --soc-fw FILENAME EL3 Runtime Firmware BL31 + --tos-fw FILENAME Secure Payload BL32 (Trusted OS) + --nt-fw FILENAME Non-Trusted Firmware BL33 + --rot-cert FILENAME Root Of Trust key certificate + --trusted-key-cert FILENAME Trusted key certificate + --scp-fw-key-cert FILENAME SCP Firmware key certificate + --soc-fw-key-cert FILENAME SoC Firmware key certificate + --tos-fw-key-cert FILENAME Trusted OS Firmware key certificate + --nt-fw-key-cert FILENAME Non-Trusted Firmware key certificate + --tb-fw-cert FILENAME Trusted Boot Firmware BL2 certificate + --scp-fw-cert FILENAME SCP Firmware content certificate + --soc-fw-cert FILENAME SoC Firmware content certificate + --tos-fw-cert FILENAME Trusted OS Firmware content certificate + --nt-fw-cert FILENAME Non-Trusted Firmware content certificate +EOF + exit +} + +echo "!! The fip_create tool is deprecated. Use the new fiptool. !!" +basedir="$(dirname $0)/../fiptool" +fiptool_args= +while :; do + case "$1" in + -h | --help ) + usage + break ;; + -d | --dump ) + fiptool_args="info $fiptool_args" + shift ;; + -u | --unpack ) + fiptool_args="unpack $fiptool_args" + shift ;; + -f | --force ) + fiptool_args="$fiptool_args --force" + shift ;; + --scp-fwu-cfg | \ + --ap-fwu-cfg | \ + --fwu | \ + --fwu-cert | \ + --tb-fw | \ + --scp-fw | \ + --soc-fw | \ + --tos-fw | \ + --nt-fw | \ + --rot-cert | \ + --trusted-key-cert | \ + --scp-fw-key-cert | \ + --soc-fw-key-cert | \ + --tos-fw-key-cert | \ + --nt-fw-key-cert | \ + --tb-fw-cert | \ + --scp-fw-cert | \ + --soc-fw-cert | \ + --tos-fw-cert | \ + --nt-fw-cert ) + fiptool_args="$fiptool_args $1" + shift + if test -z $1; then + usage + fi + fiptool_args="$fiptool_args $1" + shift ;; + * ) + break ;; + esac +done + +# expect a FIP filename +if test -z $1; then + usage +fi + +is_pack_cmd=1 +for arg in $fiptool_args; do + case "$arg" in + unpack ) + is_pack_cmd=0 + break ;; + info ) + is_pack_cmd=0 + break ;; + * ) + esac +done + +# if --unpack and --dump were not specified +# the default action is to pack +if test "$is_pack_cmd" -eq 1; then + fiptool_args="update $fiptool_args" +fi + +# append FIP filename +fiptool_args="$fiptool_args $1" +echo "Invoking fiptool with args: $fiptool_args" +"$basedir/fiptool" $fiptool_args diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c new file mode 100644 index 0000000..4a3e61a --- /dev/null +++ b/tools/fiptool/fiptool.c @@ -0,0 +1,977 @@ +/* + * Copyright (c) 2016, 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fiptool.h" +#include "firmware_image_package.h" +#include "tbbr_config.h" + +#define OPT_TOC_ENTRY 0 +#define OPT_PLAT_TOC_FLAGS 1 + +static int info_cmd(int argc, char *argv[]); +static void info_usage(void); +static int create_cmd(int argc, char *argv[]); +static void create_usage(void); +static int update_cmd(int argc, char *argv[]); +static void update_usage(void); +static int unpack_cmd(int argc, char *argv[]); +static void unpack_usage(void); +static int remove_cmd(int argc, char *argv[]); +static void remove_usage(void); +static int version_cmd(int argc, char *argv[]); +static void version_usage(void); +static int help_cmd(int argc, char *argv[]); +static void usage(void); + +/* Available subcommands. */ +static cmd_t cmds[] = { + { .name = "info", .handler = info_cmd, .usage = info_usage }, + { .name = "create", .handler = create_cmd, .usage = create_usage }, + { .name = "update", .handler = update_cmd, .usage = update_usage }, + { .name = "unpack", .handler = unpack_cmd, .usage = unpack_usage }, + { .name = "remove", .handler = remove_cmd, .usage = remove_usage }, + { .name = "version", .handler = version_cmd, .usage = version_usage }, + { .name = "help", .handler = help_cmd, .usage = NULL }, +}; + +static image_t *images[MAX_IMAGES]; +static size_t nr_images; +static uuid_t uuid_null = { 0 }; +static int verbose; + +static void vlog(int prio, char *msg, va_list ap) +{ + char *prefix[] = { "DEBUG", "WARN", "ERROR" }; + + fprintf(stderr, "%s: ", prefix[prio]); + vfprintf(stderr, msg, ap); + fputc('\n', stderr); +} + +static void log_dbgx(char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vlog(LOG_DBG, msg, ap); + va_end(ap); +} + +static void log_warnx(char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vlog(LOG_WARN, msg, ap); + va_end(ap); +} + +static void log_err(char *msg, ...) +{ + char buf[512]; + va_list ap; + + va_start(ap, msg); + snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); + vlog(LOG_ERR, buf, ap); + va_end(ap); + exit(1); +} + +static void log_errx(char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vlog(LOG_ERR, msg, ap); + va_end(ap); + exit(1); +} + +static void add_image(image_t *image) +{ + if (nr_images + 1 > MAX_IMAGES) + log_errx("Too many images"); + images[nr_images++] = image; +} + +static void free_image(image_t *image) +{ + free(image->buffer); + free(image); +} + +static void replace_image(image_t *image_dst, image_t *image_src) +{ + int i; + + for (i = 0; i < nr_images; i++) { + if (images[i] == image_dst) { + free_image(images[i]); + images[i] = image_src; + break; + } + } + assert(i != nr_images); +} + +static void remove_image(image_t *image) +{ + int i; + + for (i = 0; i < nr_images; i++) { + if (images[i] == image) { + free_image(images[i]); + images[i] = NULL; + break; + } + } + assert(i != nr_images); + + /* Compact array. */ + memmove(&images[i], &images[i + 1], + (nr_images - i - 1) * sizeof(*images)); + nr_images--; +} + +static void free_images(void) +{ + int i; + + for (i = 0; i < nr_images; i++) { + free_image(images[i]); + images[i] = NULL; + } +} + +static toc_entry_t *get_entry_lookup_from_uuid(const uuid_t *uuid) +{ + toc_entry_t *toc_entry = toc_entries; + + for (; toc_entry->cmdline_name != NULL; toc_entry++) + if (memcmp(&toc_entry->uuid, uuid, sizeof(uuid_t)) == 0) + return toc_entry; + return NULL; +} + +static int parse_fip(char *filename, fip_toc_header_t *toc_header_out) +{ + struct stat st; + FILE *fp; + char *buf, *bufend; + fip_toc_header_t *toc_header; + fip_toc_entry_t *toc_entry; + image_t *image; + int terminated = 0; + + fp = fopen(filename, "r"); + if (fp == NULL) + log_err("fopen %s", filename); + + if (fstat(fileno(fp), &st) == -1) + log_err("fstat %s", filename); + + buf = malloc(st.st_size); + if (buf == NULL) + log_err("malloc"); + + if (fread(buf, 1, st.st_size, fp) != st.st_size) + log_errx("Failed to read %s", filename); + bufend = buf + st.st_size; + fclose(fp); + + if (st.st_size < sizeof(fip_toc_header_t)) + log_errx("FIP %s is truncated", filename); + + toc_header = (fip_toc_header_t *)buf; + toc_entry = (fip_toc_entry_t *)(toc_header + 1); + + if (toc_header->name != TOC_HEADER_NAME) + log_errx("%s is not a FIP file", filename); + + /* Return the ToC header if the caller wants it. */ + if (toc_header_out != NULL) + *toc_header_out = *toc_header; + + /* Walk through each ToC entry in the file. */ + while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) { + /* Found the ToC terminator, we are done. */ + if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) { + terminated = 1; + break; + } + + /* + * Build a new image out of the ToC entry and add it to the + * table of images. + */ + image = malloc(sizeof(*image)); + if (image == NULL) + log_err("malloc"); + + memcpy(&image->uuid, &toc_entry->uuid, sizeof(uuid_t)); + + image->buffer = malloc(toc_entry->size); + if (image->buffer == NULL) + log_err("malloc"); + + /* Overflow checks before memory copy. */ + if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) + log_errx("FIP %s is corrupted", filename); + if (toc_entry->size + toc_entry->offset_address > st.st_size) + log_errx("FIP %s is corrupted", filename); + + memcpy(image->buffer, buf + toc_entry->offset_address, + toc_entry->size); + image->size = toc_entry->size; + + image->toc_entry = get_entry_lookup_from_uuid(&toc_entry->uuid); + if (image->toc_entry == NULL) { + add_image(image); + toc_entry++; + continue; + } + + assert(image->toc_entry->image == NULL); + /* Link backpointer from lookup entry. */ + image->toc_entry->image = image; + add_image(image); + + toc_entry++; + } + + if (terminated == 0) + log_errx("FIP %s does not have a ToC terminator entry", + filename); + free(buf); + return 0; +} + +static image_t *read_image_from_file(toc_entry_t *toc_entry, char *filename) +{ + struct stat st; + image_t *image; + FILE *fp; + + fp = fopen(filename, "r"); + if (fp == NULL) + log_err("fopen %s", filename); + + if (fstat(fileno(fp), &st) == -1) + log_errx("fstat %s", filename); + + image = malloc(sizeof(*image)); + if (image == NULL) + log_err("malloc"); + + memcpy(&image->uuid, &toc_entry->uuid, sizeof(uuid_t)); + + image->buffer = malloc(st.st_size); + if (image->buffer == NULL) + log_err("malloc"); + if (fread(image->buffer, 1, st.st_size, fp) != st.st_size) + log_errx("Failed to read %s", filename); + image->size = st.st_size; + image->toc_entry = toc_entry; + + fclose(fp); + return image; +} + +static int write_image_to_file(image_t *image, char *filename) +{ + FILE *fp; + + fp = fopen(filename, "w"); + if (fp == NULL) + log_err("fopen"); + if (fwrite(image->buffer, 1, image->size, fp) != image->size) + log_errx("Failed to write %s", filename); + fclose(fp); + return 0; +} + +static int fill_common_opts(struct option *opts, int has_arg) +{ + int i; + + for (i = 0; toc_entries[i].cmdline_name != NULL; i++) { + opts[i].name = toc_entries[i].cmdline_name; + opts[i].has_arg = has_arg; + opts[i].flag = NULL; + opts[i].val = 0; + } + return i; +} + +static void add_opt(struct option *opts, int idx, char *name, + int has_arg, int val) +{ + opts[idx].name = name; + opts[idx].has_arg = has_arg; + opts[idx].flag = NULL; + opts[idx].val = val; +} + +static int info_cmd(int argc, char *argv[]) +{ + image_t *image; + uint64_t image_offset; + uint64_t image_size = 0; + fip_toc_header_t toc_header; + int i; + + if (argc != 2) + usage(); + argc--, argv++; + + parse_fip(argv[0], &toc_header); + + if (verbose) { + log_dbgx("toc_header[name]: 0x%llX", + (unsigned long long)toc_header.name); + log_dbgx("toc_header[serial_number]: 0x%llX", + (unsigned long long)toc_header.serial_number); + log_dbgx("toc_header[flags]: 0x%llX", + (unsigned long long)toc_header.flags); + } + + image_offset = sizeof(fip_toc_header_t) + + (sizeof(fip_toc_entry_t) * (nr_images + 1)); + + for (i = 0; i < nr_images; i++) { + image = images[i]; + if (image->toc_entry != NULL) + printf("%s: ", image->toc_entry->name); + else + printf("Unknown entry: "); + image_size = image->size; + printf("offset=0x%llX, size=0x%llX", + (unsigned long long)image_offset, + (unsigned long long)image_size); + if (image->toc_entry != NULL) + printf(", cmdline=\"--%s\"\n", + image->toc_entry->cmdline_name); + else + putchar('\n'); + image_offset += image_size; + } + + free_images(); + return 0; +} + +static void info_usage(void) +{ + printf("fiptool info FIP_FILENAME\n"); +} + +static int pack_images(char *filename, uint64_t toc_flags) +{ + FILE *fp; + image_t *image; + fip_toc_header_t *toc_header; + fip_toc_entry_t *toc_entry; + char *buf; + uint64_t entry_offset, buf_size, payload_size; + int i; + + /* Calculate total payload size and allocate scratch buffer. */ + payload_size = 0; + for (i = 0; i < nr_images; i++) + payload_size += images[i]->size; + + buf_size = sizeof(fip_toc_header_t) + + sizeof(fip_toc_entry_t) * (nr_images + 1); + buf = calloc(1, buf_size); + if (buf == NULL) + log_err("calloc"); + + /* Build up header and ToC entries from the image table. */ + toc_header = (fip_toc_header_t *)buf; + toc_header->name = TOC_HEADER_NAME; + toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER; + toc_header->flags = toc_flags; + + toc_entry = (fip_toc_entry_t *)(toc_header + 1); + + entry_offset = buf_size; + for (i = 0; i < nr_images; i++) { + image = images[i]; + memcpy(&toc_entry->uuid, &image->uuid, sizeof(uuid_t)); + toc_entry->offset_address = entry_offset; + toc_entry->size = image->size; + toc_entry->flags = 0; + entry_offset += toc_entry->size; + toc_entry++; + } + + /* Append a null uuid entry to mark the end of ToC entries. */ + memcpy(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)); + toc_entry->offset_address = entry_offset; + toc_entry->size = 0; + toc_entry->flags = 0; + + /* Generate the FIP file. */ + fp = fopen(filename, "w"); + if (fp == NULL) + log_err("fopen %s", filename); + + if (verbose) + log_dbgx("Metadata size: %zu bytes", buf_size); + + if (fwrite(buf, 1, buf_size, fp) != buf_size) + log_errx("Failed to write image to %s", filename); + free(buf); + + if (verbose) + log_dbgx("Payload size: %zu bytes", payload_size); + + for (i = 0; i < nr_images; i++) { + image = images[i]; + if (fwrite(image->buffer, 1, image->size, fp) != image->size) + log_errx("Failed to write image to %s", filename); + } + + fclose(fp); + return 0; +} + +/* + * This function is shared between the create and update subcommands. + * The difference between the two subcommands is that when the FIP file + * is created, the parsing of an existing FIP is skipped. This results + * in update_fip() creating the new FIP file from scratch because the + * internal image table is not populated. + */ +static void update_fip(void) +{ + toc_entry_t *toc_entry; + image_t *image; + + /* Add or replace images in the FIP file. */ + for (toc_entry = toc_entries; + toc_entry->cmdline_name != NULL; + toc_entry++) { + if (toc_entry->action != DO_PACK) + continue; + + image = read_image_from_file(toc_entry, toc_entry->action_arg); + if (toc_entry->image != NULL) { + if (verbose) + log_dbgx("Replacing image %s.bin with %s", + toc_entry->cmdline_name, + toc_entry->action_arg); + replace_image(toc_entry->image, image); + } else { + if (verbose) + log_dbgx("Adding image %s", + toc_entry->action_arg); + add_image(image); + } + /* Link backpointer from lookup entry. */ + toc_entry->image = image; + + free(toc_entry->action_arg); + toc_entry->action_arg = NULL; + } +} + +static void parse_plat_toc_flags(char *arg, unsigned long long *toc_flags) +{ + unsigned long long flags; + char *endptr; + + errno = 0; + flags = strtoull(arg, &endptr, 16); + if (*endptr != '\0' || flags > UINT16_MAX || errno != 0) + log_errx("Invalid platform ToC flags: %s", arg); + /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */ + *toc_flags |= flags << 32; +} + +static int create_cmd(int argc, char *argv[]) +{ + struct option opts[toc_entries_len + 1]; + unsigned long long toc_flags = 0; + int i; + + if (argc < 2) + usage(); + + i = fill_common_opts(opts, required_argument); + add_opt(opts, i, "plat-toc-flags", required_argument, + OPT_PLAT_TOC_FLAGS); + add_opt(opts, ++i, NULL, 0, 0); + + while (1) { + int c, opt_index; + + c = getopt_long(argc, argv, "o:", opts, &opt_index); + if (c == -1) + break; + + switch (c) { + case OPT_TOC_ENTRY: { + toc_entry_t *toc_entry; + + toc_entry = &toc_entries[opt_index]; + toc_entry->action = DO_PACK; + toc_entry->action_arg = strdup(optarg); + if (toc_entry->action_arg == NULL) + log_err("strdup"); + break; + } + case OPT_PLAT_TOC_FLAGS: + parse_plat_toc_flags(optarg, &toc_flags); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + + update_fip(); + + pack_images(argv[0], toc_flags); + free_images(); + return 0; +} + +static void create_usage(void) +{ + toc_entry_t *toc_entry = toc_entries; + + printf("fiptfool create [--plat-toc-flags ] [opts] FIP_FILENAME\n"); + printf(" --plat-toc-flags \t16-bit platform specific flag field " + "occupying bits 32-47 in 64-bit ToC header.\n"); + fputc('\n', stderr); + printf("Specific images are packed with the following options:\n"); + for (; toc_entry->cmdline_name != NULL; toc_entry++) + printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, + toc_entry->name); +} + +static int update_cmd(int argc, char *argv[]) +{ + struct option opts[toc_entries_len + 2]; + char outfile[FILENAME_MAX] = { 0 }; + fip_toc_header_t toc_header = { 0 }; + unsigned long long toc_flags = 0; + int pflag = 0; + int i; + + if (argc < 2) + usage(); + + i = fill_common_opts(opts, required_argument); + add_opt(opts, i, "out", required_argument, 'o'); + add_opt(opts, ++i, "plat-toc-flags", required_argument, + OPT_PLAT_TOC_FLAGS); + add_opt(opts, ++i, NULL, 0, 0); + + while (1) { + int c, opt_index; + + c = getopt_long(argc, argv, "o:", opts, &opt_index); + if (c == -1) + break; + + switch (c) { + case OPT_TOC_ENTRY: { + toc_entry_t *toc_entry; + + toc_entry = &toc_entries[opt_index]; + toc_entry->action = DO_PACK; + toc_entry->action_arg = strdup(optarg); + if (toc_entry->action_arg == NULL) + log_err("strdup"); + break; + } + case OPT_PLAT_TOC_FLAGS: { + parse_plat_toc_flags(optarg, &toc_flags); + pflag = 1; + break; + } + case 'o': + snprintf(outfile, sizeof(outfile), "%s", optarg); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + + if (outfile[0] == '\0') + snprintf(outfile, sizeof(outfile), "%s", argv[0]); + + if (access(outfile, F_OK) == 0) + parse_fip(argv[0], &toc_header); + + if (pflag) + toc_header.flags &= ~(0xffffULL << 32); + toc_flags = (toc_header.flags |= toc_flags); + + update_fip(); + + pack_images(outfile, toc_flags); + free_images(); + return 0; +} + +static void update_usage(void) +{ + toc_entry_t *toc_entry = toc_entries; + + printf("fiptfool update [--out FIP_FILENAME] " + "[--plat-toc-flags ] [opts] FIP_FILENAME\n"); + printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n"); + printf(" --plat-toc-flags \t16-bit platform specific flag field " + "occupying bits 32-47 in 64-bit ToC header.\n"); + fputc('\n', stderr); + printf("Specific images are packed with the following options:\n"); + for (; toc_entry->cmdline_name != NULL; toc_entry++) + printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, + toc_entry->name); +} + +static int unpack_cmd(int argc, char *argv[]) +{ + struct option opts[toc_entries_len + 3]; + char file[FILENAME_MAX], outdir[PATH_MAX] = { 0 }; + toc_entry_t *toc_entry; + int fflag = 0; + int unpack_all = 1; + int i; + + if (argc < 2) + usage(); + + i = fill_common_opts(opts, required_argument); + add_opt(opts, i, "force", no_argument, 'f'); + add_opt(opts, ++i, "out", required_argument, 'o'); + add_opt(opts, ++i, NULL, 0, 0); + + while (1) { + int c, opt_index; + + c = getopt_long(argc, argv, "fo:", opts, &opt_index); + if (c == -1) + break; + + switch (c) { + case OPT_TOC_ENTRY: + unpack_all = 0; + toc_entry = &toc_entries[opt_index]; + toc_entry->action = DO_UNPACK; + toc_entry->action_arg = strdup(optarg); + if (toc_entry->action_arg == NULL) + log_err("strdup"); + break; + case 'f': + fflag = 1; + break; + case 'o': + snprintf(outdir, sizeof(outdir), "%s", optarg); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + + parse_fip(argv[0], NULL); + + if (outdir[0] != '\0') + if (chdir(outdir) == -1) + log_err("chdir %s", outdir); + + /* Mark all images to be unpacked. */ + if (unpack_all) { + for (toc_entry = toc_entries; + toc_entry->cmdline_name != NULL; + toc_entry++) { + if (toc_entry->image != NULL) { + toc_entry->action = DO_UNPACK; + toc_entry->action_arg = NULL; + } + } + } + + /* Unpack all specified images. */ + for (toc_entry = toc_entries; + toc_entry->cmdline_name != NULL; + toc_entry++) { + if (toc_entry->action != DO_UNPACK) + continue; + + /* Build filename. */ + if (toc_entry->action_arg == NULL) + snprintf(file, sizeof(file), "%s.bin", + toc_entry->cmdline_name); + else + snprintf(file, sizeof(file), "%s", + toc_entry->action_arg); + + if (toc_entry->image == NULL) { + log_warnx("Requested image %s is not in %s", + file, argv[0]); + free(toc_entry->action_arg); + toc_entry->action_arg = NULL; + continue; + } + + if (access(file, F_OK) != 0 || fflag) { + if (verbose) + log_dbgx("Unpacking %s", file); + write_image_to_file(toc_entry->image, file); + } else { + log_warnx("File %s already exists, use --force to overwrite it", + file); + } + + free(toc_entry->action_arg); + toc_entry->action_arg = NULL; + } + + free_images(); + return 0; +} + +static void unpack_usage(void) +{ + toc_entry_t *toc_entry = toc_entries; + + printf("fiptool unpack [--force] [--out ] [opts] FIP_FILENAME\n"); + printf(" --force\tIf the output file already exists, use --force to " + "overwrite it.\n"); + printf(" --out path\tSet the output directory path.\n"); + fputc('\n', stderr); + printf("Specific images are unpacked with the following options:\n"); + for (; toc_entry->cmdline_name != NULL; toc_entry++) + printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, + toc_entry->name); + fputc('\n', stderr); + printf("If no options are provided, all images will be unpacked.\n"); +} + +static int remove_cmd(int argc, char *argv[]) +{ + struct option opts[toc_entries_len + 2]; + char outfile[FILENAME_MAX] = { 0 }; + fip_toc_header_t toc_header; + toc_entry_t *toc_entry; + int fflag = 0; + int i; + + if (argc < 2) + usage(); + + i = fill_common_opts(opts, no_argument); + add_opt(opts, i, "force", no_argument, 'f'); + add_opt(opts, ++i, "out", required_argument, 'o'); + add_opt(opts, ++i, NULL, 0, 0); + + while (1) { + int c, opt_index; + + c = getopt_long(argc, argv, "fo:", opts, &opt_index); + if (c == -1) + break; + + switch (c) { + case OPT_TOC_ENTRY: + toc_entry = &toc_entries[opt_index]; + toc_entry->action = DO_REMOVE; + break; + case 'f': + fflag = 1; + break; + case 'o': + snprintf(outfile, sizeof(outfile), "%s", optarg); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + usage(); + + if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag) + log_errx("File %s already exists, use --force to overwrite it", + outfile); + + if (outfile[0] == '\0') + snprintf(outfile, sizeof(outfile), "%s", argv[0]); + + parse_fip(argv[0], &toc_header); + + for (toc_entry = toc_entries; + toc_entry->cmdline_name != NULL; + toc_entry++) { + if (toc_entry->action != DO_REMOVE) + continue; + if (toc_entry->image != NULL) { + if (verbose) + log_dbgx("Removing %s.bin", + toc_entry->cmdline_name); + remove_image(toc_entry->image); + } else { + log_warnx("Requested image %s.bin is not in %s", + toc_entry->cmdline_name, argv[0]); + } + } + + pack_images(outfile, toc_header.flags); + free_images(); + return 0; +} + +static void remove_usage(void) +{ + toc_entry_t *toc_entry = toc_entries; + + printf("fiptool remove [--force] [--out FIP_FILENAME] [opts] FIP_FILENAME\n"); + printf(" --force\t\tIf the output FIP file already exists, use --force to " + "overwrite it.\n"); + printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n"); + fputc('\n', stderr); + printf("Specific images are removed with the following options:\n"); + for (; toc_entry->cmdline_name != NULL; toc_entry++) + printf(" --%-16s\t%s\n", toc_entry->cmdline_name, + toc_entry->name); +} + +static int version_cmd(int argc, char *argv[]) +{ +#ifdef VERSION + puts(VERSION); +#else + /* If built from fiptool directory, VERSION is not set. */ + puts("Unknown version"); +#endif + return 0; +} + +static void version_usage(void) +{ + printf("fiptool version\n"); +} + +static int help_cmd(int argc, char *argv[]) +{ + int i; + + if (argc < 2) + usage(); + argc--, argv++; + + for (i = 0; i < NELEM(cmds); i++) { + if (strcmp(cmds[i].name, argv[0]) == 0 && + cmds[i].usage != NULL) { + cmds[i].usage(); + break; + } + } + if (i == NELEM(cmds)) + printf("No help for subcommand '%s'\n", argv[0]); + return 0; +} + +static void usage(void) +{ + printf("usage: [--verbose] fiptool []\n"); + printf("Global options supported:\n"); + printf(" --verbose\tEnable verbose output for all commands.\n"); + fputc('\n', stderr); + printf("Commands supported:\n"); + printf(" info\t\tList images contained in FIP.\n"); + printf(" create\tCreate a new FIP with the given images.\n"); + printf(" update\tUpdate an existing FIP with the given images.\n"); + printf(" unpack\tUnpack images from FIP.\n"); + printf(" remove\tRemove images from FIP.\n"); + printf(" version\tShow fiptool version.\n"); + printf(" help\t\tShow help for given command.\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int i, ret = 0; + + if (argc < 2) + usage(); + argc--, argv++; + + if (strcmp(argv[0], "-v") == 0 || + strcmp(argv[0], "--verbose") == 0) { + verbose = 1; + argc--, argv++; + } + + for (i = 0; i < NELEM(cmds); i++) { + if (strcmp(cmds[i].name, argv[0]) == 0) { + ret = cmds[i].handler(argc, argv); + break; + } + } + if (i == NELEM(cmds)) + usage(); + return ret; +} diff --git a/tools/fiptool/fiptool.h b/tools/fiptool/fiptool.h new file mode 100644 index 0000000..0fe64c0 --- /dev/null +++ b/tools/fiptool/fiptool.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, 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 __FIPTOOL_H__ +#define __FIPTOOL_H__ + +#include +#include + +#include "uuid.h" + +#define NELEM(x) (sizeof (x) / sizeof *(x)) + +/* TODO: Do not hardcode, use realloc() */ +#define MAX_IMAGES 32 + +enum { + DO_PACK = 1, + DO_UNPACK = 2, + DO_REMOVE = 3 +}; + +enum { + LOG_DBG, + LOG_WARN, + LOG_ERR +}; + +typedef struct image { + uuid_t uuid; + size_t size; + void *buffer; + struct toc_entry *toc_entry; +} image_t; + +typedef struct cmd { + char *name; + int (*handler)(int, char **); + void (*usage)(void); +} cmd_t; + +#endif /* __FIPTOOL_H__ */ diff --git a/tools/fiptool/tbbr_config.c b/tools/fiptool/tbbr_config.c new file mode 100644 index 0000000..e8fbbba --- /dev/null +++ b/tools/fiptool/tbbr_config.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, 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 + +#include "firmware_image_package.h" +#include "tbbr_config.h" + +/* The images used depends on the platform. */ +toc_entry_t toc_entries[] = { + { "SCP Firmware Updater Configuration FWU SCP_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U, + "scp-fwu-cfg", NULL, 0, NULL }, + { "AP Firmware Updater Configuration BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U, + "ap-fwu-cfg", NULL, 0, NULL }, + { "Firmware Updater NS_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U, + "fwu", NULL, 0, NULL }, + { "Non-Trusted Firmware Updater certificate", UUID_TRUSTED_FWU_CERT, + "fwu-cert", NULL, 0, NULL }, + { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2, + "tb-fw", NULL, 0, NULL }, + { "SCP Firmware SCP_BL2", UUID_SCP_FIRMWARE_SCP_BL2, + "scp-fw", NULL, 0, NULL }, + { "EL3 Runtime Firmware BL31", UUID_EL3_RUNTIME_FIRMWARE_BL31, + "soc-fw", NULL, 0, NULL }, + { "Secure Payload BL32 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32, + "tos-fw", NULL, 0, NULL }, + { "Non-Trusted Firmware BL33", UUID_NON_TRUSTED_FIRMWARE_BL33, + "nt-fw", NULL, 0, NULL }, + /* Key Certificates */ + { "Root Of Trust key certificate", UUID_ROT_KEY_CERT, + "rot-cert", NULL, 0, NULL }, + { "Trusted key certificate", UUID_TRUSTED_KEY_CERT, + "trusted-key-cert", NULL, 0, NULL }, + { "SCP Firmware key certificate", UUID_SCP_FW_KEY_CERT, + "scp-fw-key-cert", NULL, 0, NULL }, + { "SoC Firmware key certificate", UUID_SOC_FW_KEY_CERT, + "soc-fw-key-cert", NULL, 0, NULL }, + { "Trusted OS Firmware key certificate", UUID_TRUSTED_OS_FW_KEY_CERT, + "tos-fw-key-cert", NULL, 0, NULL }, + { "Non-Trusted Firmware key certificate", UUID_NON_TRUSTED_FW_KEY_CERT, + "nt-fw-key-cert", NULL, 0, NULL }, + /* Content certificates */ + { "Trusted Boot Firmware BL2 certificate", UUID_TRUSTED_BOOT_FW_CERT, + "tb-fw-cert", NULL, 0, NULL }, + { "SCP Firmware content certificate", UUID_SCP_FW_CONTENT_CERT, + "scp-fw-cert", NULL, 0, NULL }, + { "SoC Firmware content certificate", UUID_SOC_FW_CONTENT_CERT, + "soc-fw-cert", NULL, 0, NULL }, + { "Trusted OS Firmware content certificate", UUID_TRUSTED_OS_FW_CONTENT_CERT, + "tos-fw-cert", NULL, 0, NULL }, + { "Non-Trusted Firmware content certificate", UUID_NON_TRUSTED_FW_CONTENT_CERT, + "nt-fw-cert", NULL, 0, NULL }, + { NULL, { 0 }, NULL, NULL, 0, NULL } +}; + +size_t toc_entries_len = sizeof(toc_entries) / sizeof(toc_entries[0]); diff --git a/tools/fiptool/tbbr_config.h b/tools/fiptool/tbbr_config.h new file mode 100644 index 0000000..d771a9b --- /dev/null +++ b/tools/fiptool/tbbr_config.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 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 __TBBR_CONFIG_H__ +#define __TBBR_CONFIG_H__ + +#include + +#include "uuid.h" + +/* TODO: Update this number as required */ +#define TOC_HEADER_SERIAL_NUMBER 0x12345678 + +typedef struct toc_entry { + const char *name; + uuid_t uuid; + const char *cmdline_name; + struct image *image; + int action; + char *action_arg; +} toc_entry_t; + +extern toc_entry_t toc_entries[]; +extern size_t toc_entries_len; + +#endif /* __TBBR_CONFIG_H__ */