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