"vscode:/vscode.git/clone" did not exist on "d76258ff554ea58d9865b9864f5fff1dd8d2e4bb"
Commit f58ad36f authored by Harry Liebel's avatar Harry Liebel Committed by Dan Handley
Browse files

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
parent 9d72b4ea
......@@ -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
......@@ -317,6 +352,7 @@ help:
@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 ""
......
/*
* 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__ */
/*-
* 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_ */
#
# 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)
/*
* 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;
}
/*
* 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__ */
../../include/firmware_image_package.h
\ No newline at end of file
../../include/stdlib/sys/uuid.h
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment