mirror of
https://github.com/CTCaer/switch-l4t-atf.git
synced 2025-03-04 16:37:34 +00:00
Merge pull request #661 from dp-arm/master
Replace fip_create with fiptool
This commit is contained in:
commit
41b568f5b3
9
.gitignore
vendored
9
.gitignore
vendored
@ -10,13 +10,14 @@ build/
|
||||
|
||||
# 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
|
||||
|
14
Makefile
14
Makefile
@ -390,7 +390,7 @@ ENABLE_PMF := 1
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Auxiliary tools (fip_create, cert_create, etc)
|
||||
# Auxiliary tools (fiptool, cert_create, etc)
|
||||
################################################################################
|
||||
|
||||
# Variables for use with Certificate Generation Tool
|
||||
@ -398,8 +398,8 @@ CRTTOOLPATH ?= tools/cert_create
|
||||
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}
|
||||
|
||||
|
||||
################################################################################
|
||||
@ -613,7 +613,8 @@ certificates: ${CRT_DEPS} ${CRTTOOL}
|
||||
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}
|
||||
@ -628,7 +629,8 @@ fwu_certificates: ${FWU_CRT_DEPS} ${CRTTOOL}
|
||||
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
|
||||
@ -639,7 +641,7 @@ fwu_fip: ${BUILD_PLAT}/${FWU_FIP_NAME}
|
||||
|
||||
.PHONY: ${FIPTOOL}
|
||||
${FIPTOOL}:
|
||||
${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH}
|
||||
${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${FIPTOOLPATH}
|
||||
|
||||
cscope:
|
||||
@echo " CSCOPE"
|
||||
|
@ -1513,11 +1513,16 @@ The ToC header and entry formats are described in the header file
|
||||
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
|
||||
@ -1534,7 +1539,7 @@ that can be loaded by the ARM Trusted Firmware from platform storage. The tool
|
||||
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)
|
||||
|
||||
|
@ -229,7 +229,7 @@ Trusted Firmware build process when `GENERATE_COT=1`. It takes the boot loader
|
||||
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.
|
||||
|
@ -269,7 +269,7 @@ performed.
|
||||
|
||||
* `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
|
||||
@ -635,7 +635,7 @@ steps:
|
||||
|
||||
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:
|
||||
|
||||
@ -643,37 +643,58 @@ Build the tool:
|
||||
|
||||
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/<platform>/<build-type>/bl2.bin \
|
||||
--soc-fw build/<platform>/<build-type>/bl31.bin \
|
||||
fip.bin
|
||||
|
||||
Example 2: view the contents of an existing Firmware package:
|
||||
|
||||
./tools/fip_create/fip_create --dump <path-to>/fip.bin
|
||||
./tools/fiptool/fiptool info <path-to>/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/<platform>/release/bl2.bin \
|
||||
build/<platform>/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 <path-to>/fip.bin
|
||||
./tools/fiptool/fiptool unpack <path-to>/fip.bin
|
||||
|
||||
Example 5: remove an entry from an existing Firmware package:
|
||||
|
||||
./tools/fiptool/fiptool remove \
|
||||
--tb-fw build/<platform>/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
|
||||
|
||||
@ -805,21 +826,21 @@ corrupted binaries.
|
||||
|
||||
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 \
|
||||
<path/to/linaro/release>/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.
|
||||
|
||||
|
@ -112,7 +112,7 @@ define IMG_BIN
|
||||
${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 @@ endef
|
||||
# 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 @@ check_$(1):
|
||||
$$(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 @@ endef
|
||||
|
||||
# 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 @@ define SOURCES_TO_OBJS
|
||||
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
|
||||
|
@ -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 @@ NTFW_NVCTR_VAL ?= 0
|
||||
$(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))
|
||||
|
||||
|
@ -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 <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"
|
||||
|
||||
/* 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;
|
||||
}
|
@ -32,10 +32,12 @@ 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
|
||||
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
|
||||
@ -43,6 +45,12 @@ else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
|
||||
ifeq (${V},0)
|
||||
Q := @
|
||||
else
|
||||
Q :=
|
||||
endif
|
||||
|
||||
# Only include from local directory (see comment below).
|
||||
INCLUDE_PATHS := -I.
|
||||
|
||||
@ -50,7 +58,7 @@ CC := gcc
|
||||
|
||||
.PHONY: all clean distclean
|
||||
|
||||
all: ${PROJECT}
|
||||
all: ${PROJECT} fip_create
|
||||
|
||||
${PROJECT}: ${OBJECTS} Makefile
|
||||
@echo " LD $@"
|
||||
@ -59,9 +67,13 @@ ${PROJECT}: ${OBJECTS} Makefile
|
||||
@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 ${CFLAGS} ${INCLUDE_PATHS} $< -o $@
|
||||
${Q}${CC} -c ${CPPFLAGS} ${CFLAGS} ${INCLUDE_PATHS} $< -o $@
|
||||
|
||||
#
|
||||
# Copy required library headers to a local directory so they can be included
|
||||
@ -76,8 +88,7 @@ firmware_image_package.h : ../../include/common/firmware_image_package.h
|
||||
$(call SHELL_COPY,$<,$@)
|
||||
|
||||
clean:
|
||||
$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
|
||||
$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS} fip_create)
|
||||
|
||||
distclean: clean
|
||||
$(call SHELL_DELETE_ALL, ${COPIED_H_FILES})
|
||||
|
148
tools/fiptool/fip_create.sh
Normal file
148
tools/fiptool/fip_create.sh
Normal file
@ -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
|
977
tools/fiptool/fiptool.c
Normal file
977
tools/fiptool/fiptool.c
Normal file
@ -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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <value>] [opts] FIP_FILENAME\n");
|
||||
printf(" --plat-toc-flags <value>\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 <value>] [opts] FIP_FILENAME\n");
|
||||
printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
|
||||
printf(" --plat-toc-flags <value>\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 <path>] [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 <command> [<args>]\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;
|
||||
}
|
69
tools/fiptool/fiptool.h
Normal file
69
tools/fiptool/fiptool.h
Normal file
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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__ */
|
83
tools/fiptool/tbbr_config.c
Normal file
83
tools/fiptool/tbbr_config.c
Normal file
@ -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 <stddef.h>
|
||||
|
||||
#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]);
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
|
||||
* 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:
|
||||
@ -28,33 +28,26 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __FIP_CREATE_H__
|
||||
#define __FIP_CREATE_H__
|
||||
#ifndef __TBBR_CONFIG_H__
|
||||
#define __TBBR_CONFIG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <uuid.h>
|
||||
|
||||
#define MAX_FILES 20
|
||||
#include "uuid.h"
|
||||
|
||||
/* TODO: Update this number as required */
|
||||
#define TOC_HEADER_SERIAL_NUMBER 0x12345678
|
||||
#define TOC_HEADER_SERIAL_NUMBER 0x12345678
|
||||
|
||||
#define FLAG_FILENAME (1 << 0)
|
||||
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;
|
||||
|
||||
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;
|
||||
extern toc_entry_t toc_entries[];
|
||||
extern size_t toc_entries_len;
|
||||
|
||||
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__ */
|
||||
#endif /* __TBBR_CONFIG_H__ */
|
Loading…
x
Reference in New Issue
Block a user