From 05ef4343d112ee7215717433af9554e6751d3e8c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 13 Feb 2018 20:29:40 +0000 Subject: [PATCH] rimage: import rimage image creation and signing tool rimage is being moved from tools repo to sof repo since there is now a cyclic dependency between both repos and sof needs rimage for it's build. Signed-off-by: Liam Girdwood --- .gitignore | 1 + Makefile.am | 4 + README | 12 +- configure.ac | 42 ++- rimage/Makefile.am | 25 ++ rimage/cse.c | 45 +++ rimage/cse.h | 42 +++ rimage/css.c | 70 +++++ rimage/css.h | 69 ++++ rimage/elf.c | 535 ++++++++++++++++++++++++++++++++ rimage/file_format.h | 117 +++++++ rimage/file_simple.c | 311 +++++++++++++++++++ rimage/hash.c | 72 +++++ rimage/keys/Makefile.am | 9 + rimage/keys/README | 34 ++ rimage/keys/otc_private_key.pem | 28 ++ rimage/keys/otc_public_key.pem | 9 + rimage/man_apl.c | 144 +++++++++ rimage/man_cnl.c | 143 +++++++++ rimage/manifest.c | 528 +++++++++++++++++++++++++++++++ rimage/manifest.h | 90 ++++++ rimage/pkcs1_5.c | 142 +++++++++ rimage/plat_auth.c | 50 +++ rimage/plat_auth.h | 92 ++++++ rimage/rimage.c | 136 ++++++++ rimage/rimage.h | 170 ++++++++++ 26 files changed, 2909 insertions(+), 11 deletions(-) create mode 100644 rimage/Makefile.am create mode 100644 rimage/cse.c create mode 100644 rimage/cse.h create mode 100644 rimage/css.c create mode 100644 rimage/css.h create mode 100644 rimage/elf.c create mode 100644 rimage/file_format.h create mode 100644 rimage/file_simple.c create mode 100644 rimage/hash.c create mode 100644 rimage/keys/Makefile.am create mode 100644 rimage/keys/README create mode 100644 rimage/keys/otc_private_key.pem create mode 100644 rimage/keys/otc_public_key.pem create mode 100644 rimage/man_apl.c create mode 100644 rimage/man_cnl.c create mode 100644 rimage/manifest.c create mode 100644 rimage/manifest.h create mode 100644 rimage/pkcs1_5.c create mode 100644 rimage/plat_auth.c create mode 100644 rimage/plat_auth.h create mode 100644 rimage/rimage.c create mode 100644 rimage/rimage.h diff --git a/.gitignore b/.gitignore index a753693f4645..5e5fea46d2f7 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ reef-* boot_ldr-* boot_module module +rimage/rimage diff --git a/Makefile.am b/Makefile.am index 82ad39e28893..7a70823eea4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,8 @@ +if BUILD_RIMAGE +SUBDIRS = rimage +else SUBDIRS = src +endif ACLOCAL_AMFLAGS = -I m4 diff --git a/README b/README index 463fc4236b35..adc23e2c379b 100644 --- a/README +++ b/README @@ -3,7 +3,13 @@ Build Instructions 1) Run "autogen.sh" -2) Run the following configure based on your platform. +2) Build and install the rimage ELF image creator and signing tool + +./configure --enable-rimage +make +sudo make install + +3) Run the following configure based on your platform. Baytrail :- @@ -20,8 +26,8 @@ headers ./configure --with-arch=host --enable-library=yes --host=x86_64-unknown-linux-gnu --prefix=$pwd/../host-root/ -3) make +4) make -4) make bin +5) make bin diff --git a/configure.ac b/configure.ac index b46f6f292773..bb4d2e9f56f3 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ AC_DEFINE_UNQUOTED([REEF_MICRO], reef_micro, [Reef micro version]) AC_CANONICAL_HOST # General compiler flags -CFLAGS="${CFLAGS:+$CFLAGS } -O2 -g -Wall -Werror -Wl,-EL -fno-inline-functions -nostdlib -Wmissing-prototypes" +CFLAGS="${CFLAGS:+$CFLAGS } -O2 -g -Wall -Werror -Wl,-EL -Wmissing-prototypes" # General assembler flags ASFLAGS="-DASSEMBLY" @@ -37,6 +37,13 @@ if test "$have_library" = "yes"; then fi AM_CONDITIONAL(BUILD_LIB, test "$have_library" = "yes") +# check if we are building tools +AC_ARG_ENABLE(rimage, [AS_HELP_STRING([--enable-rimage],[build rimage tool])], have_rimage=$enableval, have_rimage=no) +if test "$have_rimage" = "yes"; then + AC_DEFINE([CONFIG_RIMAGE], [1], [Configure to build rimage]) +fi +AM_CONDITIONAL(BUILD_RIMAGE, test "$have_rimage" = "yes") + # Architecture support AC_ARG_WITH([arch], AS_HELP_STRING([--with-arch], [Specify DSP architecture]), @@ -52,7 +59,7 @@ case "$with_arch" in AC_SUBST(XTENSA_LDFLAGS) # extra CFLAGS defined here otherwise configure working gcc tests fails. - CFLAGS="${CFLAGS:+$CFLAGS }-mlongcalls" + CFLAGS="${CFLAGS:+$CFLAGS }-fno-inline-functions -nostdlib -mlongcalls" LDFLAGS="${LDFLAGS:+$LDFLAGS }-nostdlib" #ARCH_ASFLAGS="" @@ -79,7 +86,9 @@ case "$with_arch" in AC_SUBST(ARCH) ;; *) - AC_MSG_ERROR([DSP architecture not specified]) + if test "$have_rimage" = "no"; then + AC_MSG_ERROR([DSP architecture not specified]) + fi ;; esac @@ -197,11 +206,13 @@ case "$with_platform" in AC_DEFINE([CONFIG_DMA_GW], [1], [Configure DMA Gateway]) ;; *) - if test "$ARCH" = "host"; then - PLATFORM="host" - AC_SUBST(PLATFORM) - else - AC_MSG_ERROR([Host platform not specified]) + if test "$have_rimage" = "no"; then + if test "$ARCH" = "host"; then + PLATFORM="host" + AC_SUBST(PLATFORM) + else + AC_MSG_ERROR([Host platform not specified]) + fi fi ;; esac @@ -315,12 +326,26 @@ LT_INIT AC_CHECK_TOOL([OBJCOPY], [objcopy], []) AC_CHECK_TOOL([OBJDUMP], [objdump], []) +# Check for openssl - used by rimage +AC_CHECK_LIB([crypto], [OPENSSL_config], , [have_openssl="no"]) +if test "$have_rimage" = "yes"; then + if test "$have_openssl" = "no"; then + AC_MSG_ERROR([Need OpenSSL libcrypto for rimage code signing]) + fi +fi + +PEM_KEY_PREFIX="/usr/local/share/rimage" +AC_DEFINE_UNQUOTED([PEM_KEY_PREFIX], ["$PEM_KEY_PREFIX"], ["Path for PEM keys"]) +AC_SUBST(PEM_KEY_PREFIX) + AM_EXTRA_RECURSIVE_TARGETS([bin]) AM_EXTRA_RECURSIVE_TARGETS([vminstall]) AC_CONFIG_FILES([ Makefile + rimage/Makefile + rimage/keys/Makefile src/Makefile src/tasks/Makefile src/init/Makefile @@ -380,6 +405,7 @@ echo " Target Architecture: ${ARCH} Target Platform: ${PLATFORM} Target Core: ${XTENSA_CORE} +PEM: ${PEM_KEY_PREFIX} Compiler: ${CC} CFLAGS: ${CFLAGS} diff --git a/rimage/Makefile.am b/rimage/Makefile.am new file mode 100644 index 000000000000..467bfe638b50 --- /dev/null +++ b/rimage/Makefile.am @@ -0,0 +1,25 @@ +SUBDIRS=keys + +bin_PROGRAMS = rimage + +noinst_HEADERS = \ + rimage.h \ + css.h \ + cse.h \ + plat_auth.h \ + manifest.h \ + file_format.h + +rimage_SOURCES = \ + file_simple.c \ + man_apl.c \ + man_cnl.c \ + cse.c \ + css.c \ + plat_auth.c \ + hash.c \ + pkcs1_5.c \ + manifest.c \ + elf.c \ + rimage.c + diff --git a/rimage/cse.c b/rimage/cse.c new file mode 100644 index 000000000000..b5604153f120 --- /dev/null +++ b/rimage/cse.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#include +#include "rimage.h" +#include "cse.h" +#include "manifest.h" + +void ri_cse_create(struct image *image) +{ + struct CsePartitionDirHeader *cse_hdr = image->fw_image; + struct sof_man_adsp_meta_file_ext *meta = image->fw_image + + MAN_META_EXT_OFFSET; + struct CsePartitionDirEntry *cse_entry = + image->fw_image + sizeof(*cse_hdr); + uint8_t csum = 0, *val = image->fw_image; + int i, size; + + fprintf(stdout, " cse: completing CSE manifest\n"); + + cse_entry[2].length = meta->comp_desc[0].limit_offset - + MAN_DESC_OFFSET; + + /* calculate checksum using BSD algo */ + size = sizeof(*cse_hdr) + sizeof(*cse_entry) * MAN_CSE_PARTS; + for (i = 0; i < size; i++) { + if (i == 11) + continue; + csum += val[i]; + } + cse_hdr->checksum = 0x100 - csum; +} diff --git a/rimage/cse.h b/rimage/cse.h new file mode 100644 index 000000000000..28650dadec2b --- /dev/null +++ b/rimage/cse.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __CSE_H__ +#define __CSE_H__ + +#include + +struct image; + +#define CSE_HEADER_MAKER 0x44504324 /* "DPC$" */ + +struct CsePartitionDirHeader { + uint32_t header_marker; + uint32_t nb_entries; + uint8_t header_version; + uint8_t entry_version; + uint8_t header_length; + uint8_t checksum; + uint8_t partition_name[4]; +} __attribute__((packed)); + +struct CsePartitionDirEntry { + uint8_t entry_name[12]; + uint32_t offset; + uint32_t length; + uint32_t reserved; +} __attribute__((packed)); + +void ri_cse_create(struct image *image); + +#endif diff --git a/rimage/css.c b/rimage/css.c new file mode 100644 index 000000000000..bc69cf10b55e --- /dev/null +++ b/rimage/css.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#include +#include +#include "rimage.h" +#include "css.h" +#include "manifest.h" + +void ri_css_hdr_create(struct image *image) +{ + struct css_header *css = image->fw_image + MAN_CSS_HDR_OFFSET; + struct tm *date; + struct timeval tv; + int val; + + fprintf(stdout, " cse: completing CSS manifest\n"); + + /* get local time and date */ + gettimeofday(&tv, NULL); + date = localtime(&tv.tv_sec); + date->tm_year += 1900; + fprintf(stdout, " css: set build date to %d:%2.2d:%2.2d\n", + date->tm_year, date->tm_mon, date->tm_mday); + + /* year yYyy */ + val = date->tm_year / 1000; + css->date |= val << 28; + date->tm_year -= val * 1000; + /* year yyYy */ + val = date->tm_year / 100; + css->date |= val << 24; + date->tm_year -= val * 100; + /* year yyyY */ + val = date->tm_year / 10; + css->date |= val << 20; + date->tm_year -= val * 10; + /* year Yyyy */ + val = date->tm_year; + css->date |= val << 16; + + /* month Mm - for some reason month starts at 0 */ + val = ++date->tm_mon / 10; + css->date |= val << 12; + date->tm_mon -= (val * 10); + /* month mM */ + val = date->tm_mon; + css->date |= val << 8; + + /* Day Dd */ + val = date->tm_mday / 10; + css->date |= val << 4; + date->tm_mday -= (val * 10); + /* Day dD */ + val = date->tm_mday; + css->date |= val << 0; +} diff --git a/rimage/css.h b/rimage/css.h new file mode 100644 index 000000000000..0516f531ba9a --- /dev/null +++ b/rimage/css.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __CSS_H__ +#define __CSS_H__ + +#include + +struct image; + +#define MAN_CSS_MOD_TYPE 4 +#define MAN_CSS_HDR_SIZE 161 /* in words */ +#define MAN_CSS_HDR_VERSION 0x10000 +#define MAN_CSS_MOD_VENDOR 0x8086 +#define MAN_CSS_HDR_ID {'$', 'M', 'N', '2'} + +#define MAN_CSS_KEY_SIZE (MAN_RSA_KEY_MODULUS_LEN >> 2) +#define MAN_CSS_MOD_SIZE (MAN_RSA_KEY_MODULUS_LEN >> 2) +#define MAN_CSS_EXP_SIZE (MAN_RSA_KEY_EXPONENT_LEN >> 2) +#define MAN_CSS_MAN_SIZE \ + (sizeof(struct fw_image_manifest) >> 2) + +/* + * RSA Key and Crypto + */ +#define MAN_RSA_KEY_MODULUS_LEN 256 +#define MAN_RSA_KEY_EXPONENT_LEN 4 +#define MAN_RSA_SIGNATURE_LEN 256 + +struct fw_version { + uint16_t major_version; + uint16_t minor_version; + uint16_t hotfix_version; + uint16_t build_version; +} __attribute__((packed)); + +struct css_header { + uint32_t header_type; + uint32_t header_len; + uint32_t header_version; + uint32_t reserved0; /* must be 0x0 */ + uint32_t module_vendor; + uint32_t date; + uint32_t size; + uint8_t header_id[4]; + uint32_t padding; /* must be 0x0 */ + struct fw_version version; + uint32_t svn; + uint32_t reserved1[18]; /* must be 0x0 */ + uint32_t modulus_size; + uint32_t exponent_size; + uint8_t modulus[MAN_RSA_KEY_MODULUS_LEN]; + uint8_t exponent[MAN_RSA_KEY_EXPONENT_LEN]; + uint8_t signature[MAN_RSA_SIGNATURE_LEN]; +} __attribute__((packed)); + +void ri_css_hdr_create(struct image *image); + +#endif diff --git a/rimage/elf.c b/rimage/elf.c new file mode 100644 index 000000000000..672d6e3997bc --- /dev/null +++ b/rimage/elf.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#include +#include +#include "rimage.h" +#include "cse.h" +#include "manifest.h" + +static int elf_read_sections(struct image *image, struct module *module) +{ + Elf32_Ehdr *hdr = &module->hdr; + Elf32_Shdr *section = module->section; + size_t count; + int i, ret; + uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + int man_section_idx; + + /* read in section header */ + ret = fseek(module->fd, hdr->e_shoff, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: can't seek to %s section header %d\n", + module->elf_file, ret); + return ret; + } + + /* allocate space for each section header */ + section = calloc(sizeof(Elf32_Shdr), hdr->e_shnum); + if (section == NULL) + return -ENOMEM; + module->section = section; + + /* read in sections */ + count = fread(section, sizeof(Elf32_Shdr), hdr->e_shnum, module->fd); + if (count != hdr->e_shnum) { + fprintf(stderr, "error: failed to read %s section header %d\n", + module->elf_file, -errno); + return -errno; + } + + /* find manifest module data */ + man_section_idx = elf_find_section(image, module, ".bss"); + if (man_section_idx < 0) { + return -EINVAL; + } + module->bss_index = man_section_idx; + + fprintf(stdout, " BSS module metadata section at index %d\n", + man_section_idx); + + /* parse each section */ + for (i = 0; i < hdr->e_shnum; i++) { + + /* only write valid sections */ + if (!(section[i].sh_flags & valid)) + continue; + + switch (section[i].sh_type) { + case SHT_NOBITS: + /* bss */ + module->bss_size += section[i].sh_size; + module->num_bss++; + break; + case SHT_PROGBITS: + /* text or data */ + module->fw_size += section[i].sh_size; + + if (section[i].sh_flags & SHF_EXECINSTR) + module->text_size += section[i].sh_size; + else + module->data_size += section[i].sh_size; + break; + default: + continue; + } + + module->num_sections++; + + if (!image->verbose) + continue; + + fprintf(stdout, " %s section-%d: \ttype\t 0x%8.8x\n", module->elf_file, + i, section[i].sh_type); + fprintf(stdout, " %s section-%d: \tflags\t 0x%8.8x\n", module->elf_file, + i, section[i].sh_flags); + fprintf(stdout, " %s section-%d: \taddr\t 0x%8.8x\n", module->elf_file, + i, section[i].sh_addr); + fprintf(stdout, " %s section-%d: \toffset\t 0x%8.8x\n", module->elf_file, + i, section[i].sh_offset); + fprintf(stdout, " %s section-%d: \tsize\t 0x%8.8x\n", module->elf_file, + i, section[i].sh_size); + fprintf(stdout, " %s section-%d: \tlink\t 0x%8.8x\n", module->elf_file, + i, section[i].sh_link); + fprintf(stdout, " %s section-%d: \tinfo\t 0x%8.8x\n\n", module->elf_file, + i, section[i].sh_info); + } + + return 0; +} + +static int elf_read_programs(struct image *image, struct module *module) +{ + Elf32_Ehdr *hdr = &module->hdr; + Elf32_Phdr *prg = module->prg; + size_t count; + int i, ret; + + /* read in program header */ + ret = fseek(module->fd, hdr->e_phoff, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: cant seek to %s program header %d\n", + module->elf_file, ret); + return ret; + } + + /* allocate space for programs */ + prg = calloc(sizeof(Elf32_Phdr), hdr->e_phnum); + if (prg == NULL) + return -ENOMEM; + module->prg = prg; + + /* read in programs */ + count = fread(prg, sizeof(Elf32_Phdr), hdr->e_phnum, module->fd); + if (count != hdr->e_phnum) { + fprintf(stderr, "error: failed to read %s program header %d\n", + module->elf_file, -errno); + return -errno; + } + + /* check each program */ + for (i = 0; i < hdr->e_phnum; i++) { + + if (prg[i].p_filesz == 0) + continue; + + if (!image->verbose) + continue; + + fprintf(stdout, "%s program-%d: \ttype\t 0x%8.8x\n", + module->elf_file, i, prg[i].p_type); + fprintf(stdout, "%s program-%d: \toffset\t 0x%8.8x\n", + module->elf_file, i, prg[i].p_offset); + fprintf(stdout, "%s program-%d: \tvaddr\t 0x%8.8x\n", + module->elf_file, i, prg[i].p_vaddr); + fprintf(stdout, "%s program-%d: \tpaddr\t 0x%8.8x\n", + module->elf_file, i, prg[i].p_paddr); + fprintf(stdout, "%s program-%d: \tfsize\t 0x%8.8x\n", + module->elf_file, i, prg[i].p_filesz); + fprintf(stdout, "%s program-%d: \tmsize\t 0x%8.8x\n", + module->elf_file, i, prg[i].p_memsz); + fprintf(stdout, "%s program-%d: \tflags\t 0x%8.8x\n\n", + module->elf_file, i, prg[i].p_flags); + } + + return 0; +} + +static int elf_read_hdr(struct image *image, struct module *module) +{ + Elf32_Ehdr *hdr = &module->hdr; + size_t count; + + /* read in elf header */ + count = fread(hdr, sizeof(*hdr), 1, module->fd); + if (count != 1) { + fprintf(stderr, "error: failed to read %s elf header %d\n", + module->elf_file, -errno); + return -errno; + } + + if (!image->verbose) + return 0; + + fprintf(stdout, "%s elf: \tentry point\t 0x%8.8x\n", + module->elf_file, hdr->e_entry); + fprintf(stdout, "%s elf: \tprogram offset\t 0x%8.8x\n", + module->elf_file, hdr->e_phoff); + fprintf(stdout, "%s elf: \tsection offset\t 0x%8.8x\n", + module->elf_file, hdr->e_shoff); + fprintf(stdout, "%s elf: \tprogram size\t 0x%8.8x\n", + module->elf_file, hdr->e_phentsize); + fprintf(stdout, "%s elf: \tprogram count\t 0x%8.8x\n", + module->elf_file, hdr->e_phnum); + fprintf(stdout, "%s elf: \tsection size\t 0x%8.8x\n", + module->elf_file, hdr->e_shentsize); + fprintf(stdout, "%s elf: \tsection count\t 0x%8.8x\n", + module->elf_file, hdr->e_shnum); + fprintf(stdout, "%s elf: \tstring index\t 0x%8.8x\n\n", + module->elf_file, hdr->e_shstrndx); + + return 0; +} + +int elf_is_rom(struct image *image, Elf32_Shdr *section) +{ + uint32_t start, end; + + start = section->sh_addr; + end = section->sh_addr + section->sh_size; + + if (start < image->adsp->rom_base || + start > image->adsp->rom_base + image->adsp->rom_size) + return 0; + if (end < image->adsp->rom_base || + end > image->adsp->rom_base + image->adsp->rom_size) + return 0; + return 1; +} + +static void elf_module_size(struct image *image, struct module *module, + Elf32_Shdr *section, int index) +{ + switch (section->sh_type) { + case SHT_PROGBITS: + /* text or data */ + if (section->sh_flags & SHF_EXECINSTR) { + /* text */ + if (module->text_start > section->sh_addr) + module->text_start = section->sh_addr; + if (module->text_end < section->sh_addr + section->sh_size) + module->text_end = section->sh_addr + section->sh_size; + + fprintf(stdout, "\tTEXT\n"); + } else { + /* initialized data, also calc the writable sections */ + if (module->data_start > section->sh_addr) + module->data_start = section->sh_addr; + if (module->data_end < section->sh_addr + section->sh_size) + module->data_end = section->sh_addr + section->sh_size; + + fprintf(stdout, "\tDATA\n"); + } + break; + case SHT_NOBITS: + /* bss */ + if (index == module->bss_index) { + /* updated the .bss segment */ + module->bss_start = section->sh_addr; + module->bss_end = section->sh_addr + section->sh_size; + fprintf(stdout, "\tBSS\n"); + } else { + fprintf(stdout, "\tHEAP\n"); + } + break; + default: + break; + } +} + +static void elf_module_limits(struct image *image, struct module *module) +{ + Elf32_Shdr *section; + uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + int i; + + module->text_start = module->data_start = module->bss_start = 0xffffffff; + module->text_end = module->data_end = module->bss_end = 0; + + fprintf(stdout, " Found %d sections, listing valid sections......\n", + module->hdr.e_shnum); + + fprintf(stdout, "\tNo\tStart\t\tEnd\t\tBytes\tType\n"); + + /* iterate all sections and get size of segments */ + for (i = 0; i < module->hdr.e_shnum; i++) { + + section = &module->section[i]; + + /* only check valid sections */ + if (!(section->sh_flags & valid)) + continue; + + if (section->sh_size == 0) + continue; + + if (elf_is_rom(image, section)) + continue; + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t%d", i, + section->sh_addr, section->sh_addr + section->sh_size, + section->sh_size); + + /* text or data section */ + elf_module_size(image, module, section, i); + + } + + fprintf(stdout, "\n"); +} + +/* make sure no section overlap from any modules */ +int elf_validate_section(struct image *image, struct module *module, + Elf32_Shdr *section) +{ + struct module *m; + Elf32_Shdr *s; + uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + int i, j; + + /* for each module */ + for (i = 0; i < image->num_modules; i++) { + m = &image->module[i]; + + if (m == module) + continue; + + /* for each section */ + for (j = 0; j < m->hdr.e_shnum; j++) { + s = &m->section[j]; + + if (s == section) + continue; + + /* only check valid sections */ + if (!(section->sh_flags & valid)) + continue; + + if (section->sh_size == 0) + continue; + + /* is section non overlapping ? */ + if (section->sh_addr >= s->sh_addr && + section->sh_addr + section->sh_size <= + s->sh_addr + s->sh_size) { + goto err; + } + } + } + + return 0; + +err: + fprintf(stderr, "error: section overlap between %s and %s\n", + module->elf_file, m->elf_file); + fprintf(stderr, " [0x%x : 0x%x] overlaps with [0x%x :0x%x]\n", + section->sh_addr, section->sh_addr + section->sh_size, + s->sh_addr, s->sh_addr + s->sh_size); + return -EINVAL; +} + +/* make sure no section overlaps from any modules */ +int elf_validate_modules(struct image *image) +{ + struct module *module; + Elf32_Shdr *section; + uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + int i, j, ret; + + /* for each module */ + for (i = 0; i < image->num_modules; i++) { + module = &image->module[i]; + + /* for each section */ + for (j = 0; j < module->hdr.e_shnum; j++) { + section = &module->section[j]; + + /* only check valid sections */ + if (!(section->sh_flags & valid)) + continue; + + if (section->sh_size == 0) + continue; + + /* is section non overlapping ? */ + ret = elf_validate_section(image, module, section); + if (ret < 0) + return ret; + } + } + + return 0; +} + +int elf_find_section(struct image *image, struct module *module, + const char *name) +{ + Elf32_Ehdr *hdr = &module->hdr; + Elf32_Shdr *section, *s; + char *buffer; + size_t count; + int ret, i; + + section = &module->section[hdr->e_shstrndx]; + + /* alloc data data */ + buffer = calloc(1, section->sh_size); + if (buffer == NULL) + return -ENOMEM; + + /* read in section string data */ + ret = fseek(module->fd, section->sh_offset, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: cant seek to string section %d\n", ret); + goto out; + } + + count = fread(buffer, 1, section->sh_size, module->fd); + if (count != section->sh_size) { + fprintf(stderr, "error: can't read string section %d\n", -errno); + ret = -errno; + goto out; + } + + /* find section with name */ + for (i = 0; i < hdr->e_shnum; i++) { + s = &module->section[i]; + if (!strcmp(name, buffer + s->sh_name)) { + ret = i; + goto out; + } + } + + fprintf(stderr, "error: can't find section %s in module %s\n", name, + module->elf_file); + ret = -EINVAL; + +out: + free(buffer); + return ret; +} + +int elf_parse_module(struct image *image, int module_index, const char *name) +{ + struct module *module; + uint32_t rem; + int ret = 0; + + /* validate module index */ + if (module_index >= MAX_MODULES) { + fprintf(stderr, "error: too any modules\n"); + return -EINVAL; + } + + module = &image->module[module_index]; + + /* open the elf input file */ + module->fd = fopen(name, "r"); + if (module->fd == NULL) { + fprintf(stderr, "error: unable to open %s for reading %d\n", + name, errno); + return -EINVAL; + } + module->elf_file = name; + + /* read in elf header */ + ret = elf_read_hdr(image, module); + if (ret < 0) + goto hdr_err; + + /* read in programs */ + ret = elf_read_programs(image, module); + if (ret < 0) { + fprintf(stderr, "error: failed to read program sections %d\n", + ret); + goto hdr_err; + } + + /* read sections */ + ret = elf_read_sections(image, module); + if (ret < 0) { + fprintf(stderr, "error: failed to read base sections %d\n", + ret); + goto sec_err; + } + + /* check limits */ + elf_module_limits(image, module); + + elf_find_section(image, module, ""); + + fprintf(stdout, " module: input size %d (0x%x) bytes %d sections\n", + module->fw_size, module->fw_size, module->num_sections); + fprintf(stdout, " module: text %d (0x%x) bytes\n" + " data %d (0x%x) bytes\n" + " bss %d (0x%x) bytes\n\n", + module->text_size, module->text_size, + module->data_size, module->data_size, + module->bss_size, module->bss_size); + + /* file sizes round up to nearest page */ + module->text_file_size = module->text_end - module->text_start; + rem = module->text_file_size % MAN_PAGE_SIZE; + if (rem) + module->text_file_size += MAN_PAGE_SIZE - rem; + + + /* apply any base FW fixups */ + if (image->adsp->base_fw_text_size_fixup && + module->text_start == image->adsp->sram_base) { + module->text_file_size += image->adsp->base_fw_text_size_fixup; + } + + /* data section */ + module->data_file_size = module->data_end - module->data_start; + rem = module->data_file_size % MAN_PAGE_SIZE; + if (rem) + module->data_file_size += MAN_PAGE_SIZE - rem; + + /* bss section */ + module->bss_file_size = module->bss_end - module->bss_start; + rem = module->bss_file_size % MAN_PAGE_SIZE; + if (rem) + module->bss_file_size += MAN_PAGE_SIZE - rem; + + return 0; + +sec_err: + free(module->prg); +hdr_err: + fclose(module->fd); + + return ret; +} + +void elf_free_module(struct image *image, int module_index) +{ + struct module *module = &image->module[module_index]; + + free(module->prg); + free(module->section); + fclose(module->fd); +} diff --git a/rimage/file_format.h b/rimage/file_format.h new file mode 100644 index 000000000000..15302589cc40 --- /dev/null +++ b/rimage/file_format.h @@ -0,0 +1,117 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * 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 Intel Corporation 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 + * OWNER 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. + * + * Author: Liam Girdwood + */ + + +/* + * Firmware file format . + */ + +#ifndef __INCLUDE_UAPI_SOF_FW_H__ +#define __INCLUDE_UAPI_SOF_FW_H__ + +#define SND_SOF_FW_SIG_SIZE 4 +#define SND_SOF_FW_ABI 1 +#define SND_SOF_FW_SIG "Reef" + +/* + * Firmware module is made up of 1 . N blocks of different types. The + * Block header is used to determine where and how block is to be copied in the + * DSP/host memory space. + */ +enum snd_sof_fw_blk_type { + SOF_BLK_IMAGE = 0, /* whole image - parsed by ROMs */ + SOF_BLK_TEXT = 1, + SOF_BLK_DATA = 2, + SOF_BLK_CACHE = 3, + SOF_BLK_REGS = 4, + SOF_BLK_SIG = 5, + SOF_BLK_ROM = 6, + /* add new block types here */ +}; + +struct snd_sof_blk_hdr { + enum snd_sof_fw_blk_type type; + uint32_t size; /* bytes minus this header */ + uint32_t offset; /* offset from base */ +} __attribute__((packed)); + +/* + * Firmware file is made up of 1 .. N different modules types. The module + * type is used to determine how to load and parse the module. + */ +enum snd_sof_fw_mod_type { + SOF_FW_BASE = 0, /* base firmware image */ + SOF_FW_MODULE = 1, /* firmware module */ +}; + +struct snd_sof_mod_hdr { + enum snd_sof_fw_mod_type type; + uint32_t size; /* bytes minus this header */ + uint32_t num_blocks; /* number of blocks */ +} __attribute__((packed)); + +/* + * Firmware file header. + */ +struct snd_sof_fw_header { + unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */ + uint32_t file_size; /* size of file minus this header */ + uint32_t num_modules; /* number of modules */ + uint32_t abi; /* version of header format */ +} __attribute__((packed)); + +#endif diff --git a/rimage/file_simple.c b/rimage/file_simple.c new file mode 100644 index 000000000000..dcf0d5b241b4 --- /dev/null +++ b/rimage/file_simple.c @@ -0,0 +1,311 @@ +/* + * ELF to firmware image creator. + * + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + + +#include +#include +#include +#include +#include + +#include "rimage.h" +#include "file_format.h" + +#define BYT_IRAM_BASE 0xff2c0000 +#define BYT_IRAM_HOST_OFFSET 0x0C0000 +#define BYT_IRAM_SIZE (80 * 1024) +#define BYT_DRAM_BASE 0xff300000 +#define BYT_DRAM_HOST_OFFSET 0x100000 +#define BYT_DRAM_SIZE (160 * 1024) + +#define HSW_IRAM_BASE 0x00000000 +#define HSW_IRAM_HOST_OFFSET 0x00080000 +#define HSW_IRAM_SIZE (384 * 1024) +#define HSW_DRAM_BASE 0x00400000 +#define HSW_DRAM_HOST_OFFSET 0x00000000 +#define HSW_DRAM_SIZE (512 * 1024) + +#define BDW_IRAM_BASE 0x00000000 +#define BDW_IRAM_HOST_OFFSET 0x000A0000 +#define BDW_IRAM_SIZE (320 * 1024) +#define BDW_DRAM_BASE 0x00400000 +#define BDW_DRAM_HOST_OFFSET 0x00000000 +#define BDW_DRAM_SIZE (640 * 1024) + +static int is_iram(struct image *image, Elf32_Shdr *section) +{ + const struct adsp *adsp = image->adsp; + uint32_t start, end; + + start = section->sh_addr; + end = section->sh_addr + section->sh_size; + + if (start < adsp->iram_base) + return 0; + if (start >= adsp->iram_base + adsp->iram_size) + return 0; + if (end > adsp->iram_base + adsp->iram_size) + return 0; + return 1; +} + +static int is_dram(struct image *image, Elf32_Shdr *section) +{ + const struct adsp *adsp = image->adsp; + uint32_t start, end; + + start = section->sh_addr; + end = section->sh_addr + section->sh_size; + + if (start < adsp->dram_base) + return 0; + if (start >= adsp->dram_base + adsp->dram_size) + return 0; + if (end > adsp->dram_base + adsp->dram_size) + return 0; + return 1; +} + +static int block_idx; + +static int write_block(struct image *image, struct module *module, + Elf32_Shdr *section) +{ + const struct adsp *adsp = image->adsp; + struct snd_sof_blk_hdr block; + size_t count; + void *buffer; + int ret; + + block.size = section->sh_size; + + if (is_iram(image, section)) { + block.type = SOF_BLK_TEXT; + block.offset = section->sh_addr - adsp->iram_base + + adsp->host_iram_offset; + } else if (is_dram(image, section)) { + block.type = SOF_BLK_DATA; + block.offset = section->sh_addr - adsp->dram_base + + adsp->host_dram_offset; + } else { + fprintf(stderr, "error: invalid block address/size 0x%x/0x%x\n", + section->sh_addr, section->sh_size); + return -EINVAL; + } + + /* write header */ + count = fwrite(&block, sizeof(block), 1, image->out_fd); + if (count != 1) + return -errno; + + /* alloc data data */ + buffer = calloc(1, section->sh_size); + if (buffer == NULL) + return -ENOMEM; + + /* read in section data */ + ret = fseek(module->fd, section->sh_offset, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: cant seek to section %d\n", ret); + goto out; + } + count = fread(buffer, 1, section->sh_size, module->fd); + if (count != section->sh_size) { + fprintf(stderr, "error: cant read section %d\n", -errno); + ret = -errno; + goto out; + } + + /* write out section data */ + count = fwrite(buffer, 1, section->sh_size, image->out_fd); + if (count != section->sh_size) { + fprintf(stderr, "error: cant write section %d\n", -errno); + fprintf(stderr, " foffset %d size 0x%x mem addr 0x%x\n", + section->sh_offset, section->sh_size, section->sh_addr); + ret = -errno; + goto out; + } + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%8.8lx\t%s\n", block_idx++, + section->sh_addr, section->sh_size, ftell(image->out_fd), + block.type == SOF_BLK_TEXT ? "TEXT" : "DATA"); + +out: + free(buffer); + return ret; +} + +static int simple_write_module(struct image *image, struct module *module) +{ + struct snd_sof_mod_hdr hdr; + Elf32_Shdr *section; + size_t count; + int i, err; + uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + + hdr.num_blocks = module->num_sections - module->num_bss; + hdr.size = module->text_size + module->data_size + + sizeof(struct snd_sof_blk_hdr) * hdr.num_blocks; + hdr.type = SOF_FW_BASE; + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) { + fprintf(stderr, "error: failed to write section header %d\n", + -errno); + return -errno; + } + + fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize"); + + fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->text_start, module->text_end, + module->text_end - module->text_start); + fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->data_start, module->data_end, + module->data_end - module->data_start); + fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n ", + module->bss_start, module->bss_end, + module->bss_end - module->bss_start); + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\t\tType\n"); + + for (i = 0; i < module->hdr.e_shnum; i++) { + + section = &module->section[i]; + + /* only write valid sections */ + if (!(module->section[i].sh_flags & valid)) + continue; + + /* dont write bss */ + if (section->sh_type == SHT_NOBITS) + continue; + + err = write_block(image, module, section); + if (err < 0) { + fprintf(stderr, "error: failed to write section #%d\n", i); + return err; + } + } + + fprintf(stdout, "\n"); + return 0; +} + +/* used by others */ +static int simple_write_firmware(struct image *image) +{ + struct snd_sof_fw_header hdr; + struct module *module; + size_t count; + int i, ret; + + memcpy(hdr.sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE); + + hdr.num_modules = image->num_modules; + hdr.abi = SND_SOF_FW_ABI; + hdr.file_size = 0; + + for (i = 0; i < image->num_modules; i++) { + module = &image->module[i]; + module->fw_size += sizeof(struct snd_sof_blk_hdr) * + (module->num_sections - module->num_bss); + module->fw_size += sizeof(struct snd_sof_mod_hdr) * hdr.num_modules; + hdr.file_size += module->fw_size; + } + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) + return -errno; + + for (i = 0; i < image->num_modules; i++) { + module = &image->module[i]; + + fprintf(stdout, "writing module %d %s\n", i, module->elf_file); + + ret = simple_write_module(image, module); + if (ret < 0) { + fprintf(stderr, "error: failed to write module %d\n", + i); + return ret; + } + } + + fprintf(stdout, "firmware: image size %ld (0x%lx) bytes %d modules\n\n", + hdr.file_size + sizeof(hdr), hdr.file_size + sizeof(hdr), + hdr.num_modules); + + return 0; +} + +const struct adsp machine_byt = { + .name = "byt", + .iram_base = BYT_IRAM_BASE, + .iram_size = BYT_IRAM_SIZE, + .host_iram_offset = BYT_IRAM_HOST_OFFSET, + .dram_base = BYT_DRAM_BASE, + .dram_size = BYT_DRAM_SIZE, + .host_dram_offset = BYT_DRAM_HOST_OFFSET, + .machine_id = MACHINE_BAYTRAIL, + .write_firmware = simple_write_firmware, +}; + +const struct adsp machine_cht = { + .name = "cht", + .iram_base = BYT_IRAM_BASE, + .iram_size = BYT_IRAM_SIZE, + .host_iram_offset = BYT_IRAM_HOST_OFFSET, + .dram_base = BYT_DRAM_BASE, + .dram_size = BYT_DRAM_SIZE, + .host_dram_offset = BYT_DRAM_HOST_OFFSET, + .machine_id = MACHINE_CHERRYTRAIL, + .write_firmware = simple_write_firmware, +}; + +const struct adsp machine_bsw = { + .name = "bsw", + .iram_base = BYT_IRAM_BASE, + .iram_size = BYT_IRAM_SIZE, + .host_iram_offset = BYT_IRAM_HOST_OFFSET, + .dram_base = BYT_DRAM_BASE, + .dram_size = BYT_DRAM_SIZE, + .host_dram_offset = BYT_DRAM_HOST_OFFSET, + .machine_id = MACHINE_BRASWELL, + .write_firmware = simple_write_firmware, +}; + +const struct adsp machine_hsw = { + .name = "hsw", + .iram_base = HSW_IRAM_BASE, + .iram_size = HSW_IRAM_SIZE, + .host_iram_offset = HSW_IRAM_HOST_OFFSET, + .dram_base = HSW_DRAM_BASE, + .dram_size = HSW_DRAM_SIZE, + .host_dram_offset = HSW_DRAM_HOST_OFFSET, + .machine_id = MACHINE_HASWELL, + .write_firmware = simple_write_firmware, +}; + +const struct adsp machine_bdw = { + .name = "bdw", + .iram_base = BDW_IRAM_BASE, + .iram_size = BDW_IRAM_SIZE, + .host_iram_offset = BDW_IRAM_HOST_OFFSET, + .dram_base = BDW_DRAM_BASE, + .dram_size = BDW_DRAM_SIZE, + .host_dram_offset = BDW_DRAM_HOST_OFFSET, + .machine_id = MACHINE_BROADWELL, + .write_firmware = simple_write_firmware, +}; diff --git a/rimage/hash.c b/rimage/hash.c new file mode 100644 index 000000000000..d586e07fc1b6 --- /dev/null +++ b/rimage/hash.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rimage.h" +#include "file_format.h" +#include "manifest.h" + +#define DEBUG_HASH 0 + +void module_sha256_create(struct image *image) +{ + image->md = EVP_sha256(); + image->mdctx = EVP_MD_CTX_create(); + + EVP_DigestInit_ex(image->mdctx, image->md, NULL); +} + +void module_sha256_update(struct image *image, uint8_t *data, size_t bytes) +{ + EVP_DigestUpdate(image->mdctx, data, bytes); +} + +void module_sha256_complete(struct image *image, uint8_t *hash) +{ + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; +#if DEBUG_HASH + int i; +#endif + EVP_DigestFinal_ex(image->mdctx, md_value, &md_len); + EVP_MD_CTX_destroy(image->mdctx); + + memcpy(hash, md_value, md_len); +#if DEBUG_HASH + fprintf(stdout, "Module digest is: "); + for (i = 0; i < md_len; i++) + fprintf(stdout, "%02x", md_value[i]); + fprintf(stdout, "\n"); +#endif +} + +void ri_hash(struct image *image, unsigned int offset, unsigned int size, uint8_t *hash) +{ + module_sha256_create(image); + module_sha256_update(image, image->fw_image + offset, size); + module_sha256_complete(image, hash); +} diff --git a/rimage/keys/Makefile.am b/rimage/keys/Makefile.am new file mode 100644 index 000000000000..06fe3071317a --- /dev/null +++ b/rimage/keys/Makefile.am @@ -0,0 +1,9 @@ +install-data-local: + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(PEM_KEY_PREFIX); + $(INSTALL_DATA) otc_private_key.pem $(PEM_KEY_PREFIX) + $(INSTALL_DATA) otc_public_key.pem $(PEM_KEY_PREFIX) + +EXTRA_DIST = \ + otc_private_key.pem \ + otc_public_key.pem \ No newline at end of file diff --git a/rimage/keys/README b/rimage/keys/README new file mode 100644 index 000000000000..3ece70cad290 --- /dev/null +++ b/rimage/keys/README @@ -0,0 +1,34 @@ +About +===== + +Firmware binary signing is for audio DSP is mandatory on Intel products from +Skylake onwards. i.e. no code signing on Baytrail, Cherrytrail, Braswell, +Haswell and Broadwell but mandatory on Skylake, Kabylake, Apollolake and +Cannonlake. + +rimage can now sign firmware binaries for Apollolake and Cannonlake targets. +This is done automatically as part of the "make bin" part of the build. + + +Key Pairs +========= + +The key included here is the Intel OTC (Opensource Technology Center) community +development key. It can be freely used by anyone and is intended for reference +board makers and firmware developers. + +** This key is NOT intended for locking down firmware on end user production +devices since the "private" key has been published here. A new key pair must +be genrated for securing firmware ! ** + +RSA Private and Public keys are generated as follows :- + +openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048 +openssl rsa -pubout -in private_key.pem -out public_key.pem + +The public key needs to be programmed into the OEM Key manifest (cavsManifest0) +within the BIOS in order to verify code signed with the private key. +Intel supplies tools to board makers to stitch the public key into the BIOS. + +The private key is used by rimage to sign the SOF binary. It should be kept +secret and secure for production signing. \ No newline at end of file diff --git a/rimage/keys/otc_private_key.pem b/rimage/keys/otc_private_key.pem new file mode 100644 index 000000000000..03ad749260b7 --- /dev/null +++ b/rimage/keys/otc_private_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5Q68ZJyiWWrXb +TSjlj4I/UmgusmIfv5+MCtinahekLPasIvoBhmEAr/TBizlfhj2/VN4FKNsqy7HR +QGn+iLhqnVrzpEVug4EQIpkFxTnycKMQPSDvpIqq8VL9pUCvKokSMub0oTCwoxjJ +V81wJy+NE2AnamjtnuJEXqim9U5CGjsnVNSktv/YPbso/LYFjH658Fz5QGgWfbgi +BPNFwMvemSFOIXw2J2B91ayP9ZJeI2tLyEP9EMeQqU3Gd8T5LfHIUmibpPFe1JDM +s4HmIEs7Iay03EfwjEWLVd0P/fxv9I9YNTZAi+7o8IyrTNRHDsH55efW7V58GwfS +66po4QCFAgMBAAECggEBALf7IlktTR47iRv2/WUz5hnyQWoWVmHHD6+oWc2wCzhM +Os9pkLOQ+qYPF1ZZZ6mYi5uFsVKYZ0aRsM3oVRqkNdgS2m7YtObyC2q1oRdc7JX6 +C8Wlnx69XcQzEcK4qIsMB8Gd8UQBC3RvE79nxanaEFveYP/jqb5IqdVR19SuCYCU +EZurwwAnYeLg0VSSdVQHSGVMlHkDwhgVAvp5NryPXhml51pT0gzUwnvJOsUcrc0m +tqUa2yu7/Qju1/JtFL98RgW4x3mSo4TZO3B/d664pWPOxL72zCt7bD9s06ILZmga +z1oMLMwTaNaeYIBaRvjmssKOqLXmDvfc415V82SwMYUCgYEA2p2At6acrD8Xx5GO +GeCeUbZzm0Ke9zql1W+Diq89UroFX/i9XO9Mb/ZfwouC+5n3iLjyCG7jIaIwYAyV +2qim9sINeieepM54HqYz0235nX5CqLHPDobYLn5tsbNYvXYBWiyjRppG+cnprMBk +O6vLNXNc4sRemgbcmwT3sEYLLo8CgYEA2PInWZx0JoEXriEgefv/IZeyCjpaS9uH +OOaPVAJTJPaaZhazA4ANV2bzrQAigiXbOgzPkXyldy7T7d/gHfVYnHbyhGwMEa6u +WMnj5qFXPI0hYOOrJbqXofbfGkKC996eoQybnvE0WdIwscySIki1zAenE/5nVdCJ +HLwK9xXMKasCgYA/ZxSQrsqbjgTYhVdgG+vuqOqoac7uxtyXpSrSSvaPCpJKfjp1 +PJW/lwW4x3tqewH2biUL2xUWiRJcmOnRK76YrDj6Z4k0JQljYjJ/rFKLobW1dTQm +82a5PUOVGP2wnQvRWkbUUCQrh6q0xmuLfsyFqPqUbf090KWkc/Fd90KA8wKBgG6C +q9jSAbi7ebyR02FQJJ6QD3l2UBjkMvWhPNGmfYQOuofWeEoIKMOlBevSbcGuVwYz +EGkj/YXArOQ3borUN9c8ID2kbGF1ggpojVcmSLHnkmEwmDYX3rX6c5uE1gI9vMB9 +E6jbZbd7gqKPesFMGI9eNpXQugLUv4OLpmpHCEERAoGAMF5P9jSe3JirlZ7WaH7A +I1I23L3oZfkmrcxP7B860k1ZLHDtx/MtWLkb609fq1Q2lqRuvdoaur1kW+Rv9IHS +Db8cznu9jIz3OzmJ735lHDpomylzt0+nxL5rrUnoTyMsDK0kIWs03JhPYc0+S2Ip +lkkvYQHB1eUUCxMnTgzWRr4= +-----END PRIVATE KEY----- diff --git a/rimage/keys/otc_public_key.pem b/rimage/keys/otc_public_key.pem new file mode 100644 index 000000000000..b8662bda0192 --- /dev/null +++ b/rimage/keys/otc_public_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuUOvGScollq1200o5Y+C +P1JoLrJiH7+fjArYp2oXpCz2rCL6AYZhAK/0wYs5X4Y9v1TeBSjbKsux0UBp/oi4 +ap1a86RFboOBECKZBcU58nCjED0g76SKqvFS/aVAryqJEjLm9KEwsKMYyVfNcCcv +jRNgJ2po7Z7iRF6opvVOQho7J1TUpLb/2D27KPy2BYx+ufBc+UBoFn24IgTzRcDL +3pkhTiF8NidgfdWsj/WSXiNrS8hD/RDHkKlNxnfE+S3xyFJom6TxXtSQzLOB5iBL +OyGstNxH8IxFi1XdD/38b/SPWDU2QIvu6PCMq0zURw7B+eXn1u1efBsH0uuqaOEA +hQIDAQAB +-----END PUBLIC KEY----- diff --git a/rimage/man_apl.c b/rimage/man_apl.c new file mode 100644 index 000000000000..7b32ea1c3887 --- /dev/null +++ b/rimage/man_apl.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "css.h" +#include "cse.h" +#include "plat_auth.h" +#include "manifest.h" + +/* hard coded atm - will pass this in from cmd line and git */ +#define MAN_FW_HDR_VERSION_MAJOR 9 +#define MAN_FW_HDR_VERSION_MINOR 22 +#define MAN_FW_HDR_VERSION_HOTFIX 1 +#define MAN_FW_HDR_VERSION_BUILD 0x7da + +/* manifest template */ +struct fw_image_manifest apl_manifest = { + + .cse_partition_dir_header = { + .header_marker = CSE_HEADER_MAKER, + .nb_entries = MAN_CSE_PARTS, + .header_version = 1, + .entry_version = 1, + .header_length = sizeof(struct CsePartitionDirHeader), + .checksum = 0, + .partition_name = "ADSP", + }, + + .cse_partition_dir_entry = { + { + /* CssHeader + platformFirmwareAuthenticationExtension - padding */ + .entry_name = "ADSP.man", + .offset = MAN_CSS_HDR_OFFSET, + .length = sizeof(struct css_header) + + PLAT_AUTH_SIZE, + }, + { /* ADSPMetadataFileExtension */ + .entry_name = "cavs0015.met", + .offset = MAN_META_EXT_OFFSET, + .length = sizeof(struct sof_man_adsp_meta_file_ext), + }, + { /* AdspFwBinaryDesc */ + .entry_name = "cavs0015", + .offset = MAN_FW_DESC_OFFSET, + .length = 0, /* calculated by rimage - */ + }, + + }, + + .css = { + .header_type = MAN_CSS_MOD_TYPE, + .header_len = MAN_CSS_HDR_SIZE, + .header_version = MAN_CSS_HDR_VERSION, + .module_vendor = MAN_CSS_MOD_VENDOR, + .size = 222, + .header_id = MAN_CSS_HDR_ID, + .padding = 0, + .version = { + .major_version = MAN_FW_HDR_VERSION_MAJOR, + .minor_version = MAN_FW_HDR_VERSION_MINOR, + .hotfix_version = MAN_FW_HDR_VERSION_HOTFIX, + .build_version = MAN_FW_HDR_VERSION_BUILD, + }, + .modulus_size = MAN_CSS_MOD_SIZE, + .exponent_size = MAN_CSS_EXP_SIZE, + }, + + .signed_pkg = { + .ext_type = SIGN_PKG_EXT_TYPE, + .ext_len = sizeof(struct signed_pkg_info_ext), + .name = "ADSP", + .vcn = 0, + .bitmap = {0, 0, 0, 0, 8}, + + .module[0] = { + .name = "cavs0015.met", + .meta_size = 96, + .type = 0x03, + .hash_algo = 0x02, /* SHA 256 */ + .hash_size = 0x20, + }, + }, + + .partition_info = { + + .ext_type = PART_INFO_EXT_TYPE, + .ext_len = sizeof(struct partition_info_ext), + + .name = "ADSP", + .length = 0, /* calculated by rimage - rounded up to nearest PAGE */ + .part_version = 0x10000000, + .instance_id = 1, + .reserved[0 ... 19] = 0xff, + + .module[0] = { + .name = "cavs0015.met", + .meta_size = 96, + .type = 0x03, + .reserved = {0x00, 0xff, 0xff}, + }, + + }, + + .cse_padding[0 ... 47] = 0xff, + + .adsp_file_ext = { + .ext_type = 17, + .ext_len = sizeof(struct sof_man_adsp_meta_file_ext), + .imr_type = 3, + .comp_desc[0] = { + .version = 0, + .base_offset = MAN_DESC_OFFSET, + .limit_offset = 0, /* calculated length + MAN_DESC_OFFSET */ + }, + + }, + + .reserved[0 ... 31] = 0xff, + + .desc = { + .header = { + .header_id = SOF_MAN_FW_HDR_ID, + .header_len = sizeof(struct sof_man_fw_header), + .name = SOF_MAN_FW_HDR_NAME, + .preload_page_count = 0, /* size in pages from $CPD */ + .fw_image_flags = SOF_MAN_FW_HDR_FLAGS, + .feature_mask = SOF_MAN_FW_HDR_FEATURES, + .major_version = MAN_FW_HDR_VERSION_MAJOR, + .minor_version = MAN_FW_HDR_VERSION_MINOR, + .hotfix_version = MAN_FW_HDR_VERSION_HOTFIX, + .build_version = MAN_FW_HDR_VERSION_BUILD, + .load_offset = MAN_DESC_OFFSET, + }, + }, +}; diff --git a/rimage/man_cnl.c b/rimage/man_cnl.c new file mode 100644 index 000000000000..2aec2a723d79 --- /dev/null +++ b/rimage/man_cnl.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "css.h" +#include "cse.h" +#include "plat_auth.h" +#include "manifest.h" + +/* hard coded atm - will pass this in from cmd line and git */ +#define MAN_FW_HDR_VERSION_MAJOR 10 +#define MAN_FW_HDR_VERSION_MINOR 23 +#define MAN_FW_HDR_VERSION_HOTFIX 0 +#define MAN_FW_HDR_VERSION_BUILD 0x2a4 + +/* manifest template */ +struct fw_image_manifest cnl_manifest = { + + .cse_partition_dir_header = { + .header_marker = CSE_HEADER_MAKER, + .nb_entries = MAN_CSE_PARTS, + .header_version = 1, + .entry_version = 1, + .header_length = sizeof(struct CsePartitionDirHeader), + .partition_name = "ADSP", + }, + + .cse_partition_dir_entry = { + { + /* CssHeader + platformFirmwareAuthenticationExtension - padding */ + .entry_name = "ADSP.man", + .offset = MAN_CSS_HDR_OFFSET, + .length = sizeof(struct css_header) + + PLAT_AUTH_SIZE, + }, + { /* ADSPMetadataFileExtension */ + .entry_name = "cavs0015.met", + .offset = MAN_META_EXT_OFFSET, + .length = sizeof(struct sof_man_adsp_meta_file_ext), + }, + { /* AdspFwBinaryDesc */ + .entry_name = "cavs0015", + .offset = MAN_FW_DESC_OFFSET, + .length = 0, /* calculated by rimage - */ + }, + + }, + + .css = { + .header_type = MAN_CSS_MOD_TYPE, + .header_len = MAN_CSS_HDR_SIZE, + .header_version = MAN_CSS_HDR_VERSION, + .module_vendor = MAN_CSS_MOD_VENDOR, + .size = 222, + .header_id = MAN_CSS_HDR_ID, + .padding = 0, + .version = { + .major_version = MAN_FW_HDR_VERSION_MAJOR, + .minor_version = MAN_FW_HDR_VERSION_MINOR, + .hotfix_version = MAN_FW_HDR_VERSION_HOTFIX, + .build_version = MAN_FW_HDR_VERSION_BUILD, + }, + .modulus_size = MAN_CSS_MOD_SIZE, + .exponent_size = MAN_CSS_EXP_SIZE, + }, + + .signed_pkg = { + .ext_type = SIGN_PKG_EXT_TYPE, + .ext_len = sizeof(struct signed_pkg_info_ext), + .name = "ADSP", + .vcn = 0, + .bitmap = {0, 0, 0, 0, 8}, + + .module[0] = { + .name = "cavs0015.met", + .meta_size = 96, + .type = 0x03, + .hash_algo = 0x02, /* SHA 256 */ + .hash_size = 0x20, + }, + }, + + .partition_info = { + + .ext_type = PART_INFO_EXT_TYPE, + .ext_len = sizeof(struct partition_info_ext), + + .name = "ADSP", + .length = 0, /* calculated by rimage - rounded up to nearest PAGE */ + .part_version = 0x10000000, + .instance_id = 1, + .reserved[0 ... 19] = 0xff, + + .module[0] = { + .name = "cavs0015.met", + .meta_size = 96, + .type = 0x03, + .reserved = {0x00, 0xff, 0xff}, + }, + + }, + + .cse_padding[0 ... 47] = 0xff, + + .adsp_file_ext = { + .ext_type = 17, + .ext_len = sizeof(struct sof_man_adsp_meta_file_ext), + .imr_type = 3, + .comp_desc[0] = { + .version = 0, + .base_offset = MAN_DESC_OFFSET, + .limit_offset = 0, /* calculated length + MAN_DESC_OFFSET */ + }, + + }, + + .reserved[0 ... 31] = 0xff, + + .desc = { + .header = { + .header_id = SOF_MAN_FW_HDR_ID, + .header_len = sizeof(struct sof_man_fw_header), + .name = SOF_MAN_FW_HDR_NAME, + .preload_page_count = 0, /* size in pages from $CPD */ + .fw_image_flags = SOF_MAN_FW_HDR_FLAGS, + .feature_mask = SOF_MAN_FW_HDR_FEATURES, + .major_version = MAN_FW_HDR_VERSION_MAJOR, + .minor_version = MAN_FW_HDR_VERSION_MINOR, + .hotfix_version = MAN_FW_HDR_VERSION_HOTFIX, + .build_version = MAN_FW_HDR_VERSION_BUILD, + .load_offset = 0x30000, + }, + }, +}; diff --git a/rimage/manifest.c b/rimage/manifest.c new file mode 100644 index 000000000000..a4780b780118 --- /dev/null +++ b/rimage/manifest.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Author: Liam Girdwood + * Keyon Jie + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "uapi/manifest.h" +#include "rimage.h" +#include "file_format.h" +#include "css.h" +#include "cse.h" +#include "plat_auth.h" +#include "manifest.h" + +static int man_open_rom_file(struct image *image) +{ + sprintf(image->out_rom_file, "%s.rom", image->out_file); + unlink(image->out_rom_file); + + /* allocate ROM image */ + image->rom_image = calloc(image->adsp->rom_size, 1); + if (image->rom_image == NULL) + return -ENOMEM; + + /* open ROM outfile for writing */ + image->out_rom_fd = fopen(image->out_rom_file, "w"); + if (image->out_rom_fd == NULL) { + fprintf(stderr, "error: unable to open %s for writing %d\n", + image->out_rom_file, errno); + } + + return 0; +} + +static int man_open_manifest_file(struct image *image) +{ + /* open manifest outfile for writing */ + sprintf(image->out_man_file, "%s.met", image->out_file); + unlink(image->out_man_file); + + image->out_man_fd = fopen(image->out_man_file, "w"); + if (image->out_man_fd == NULL) { + fprintf(stderr, "error: unable to open %s for writing %d\n", + image->out_man_file, errno); + } + + return 0; +} + +static int man_init_image(struct image *image) +{ + /* allocate image and copy template manifest */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (image->fw_image == NULL) + return -ENOMEM; + + memcpy(image->fw_image, image->adsp->man, + sizeof(struct fw_image_manifest)); + + return 0; +} + +/* we should call this after all segments size set up via iterate */ +static uint32_t elf_to_file_offset(struct image *image, + struct module *module, struct sof_man_module *man_module, + Elf32_Shdr *section) +{ + uint32_t elf_addr = section->sh_addr, file_offset = 0; + + if (section->sh_type == SHT_PROGBITS) { + if (section->sh_flags & SHF_EXECINSTR) { + /* text segment */ + file_offset = elf_addr - module->text_start + + module->foffset; + } else { + /* rodata segment, append to text segment */ + file_offset = elf_addr - module->data_start + + module->foffset + module->text_file_size; + + } + } else if (section->sh_type == SHT_NOBITS) { + /* bss segment */ + file_offset = 0; + } + + return file_offset; +} + +/* write SRAM sections */ +static int man_copy_sram(struct image *image, Elf32_Shdr *section, + struct module *module, struct sof_man_module *man_module, + int section_idx) +{ + uint32_t offset = elf_to_file_offset(image, module, + man_module, section); + uint32_t end = offset + section->sh_size; + int seg_type = -1; + void *buffer = image->fw_image + offset; + size_t count; + + switch (section->sh_type) { + case SHT_PROGBITS: + /* text or data */ + if (section->sh_flags & SHF_EXECINSTR) + seg_type = SOF_MAN_SEGMENT_TEXT; + else + seg_type = SOF_MAN_SEGMENT_RODATA; + break; + case SHT_NOBITS: + seg_type = SOF_MAN_SEGMENT_BSS; + default: + return 0; + } + + /* file_offset for segment should not be 0s, we set it to + * the smallest offset of its modules ATM. + */ + if (man_module->segment[seg_type].file_offset > offset || + man_module->segment[seg_type].file_offset == 0) + man_module->segment[seg_type].file_offset = offset; + + count = fread(buffer, 1, section->sh_size, module->fd); + if (count != section->sh_size) { + fprintf(stderr, "error: cant read section %d\n", -errno); + return -errno; + } + + /* get module end offset ? */ + if (end > image->image_end) + image->image_end = end; + + fprintf(stdout, "\t%d\t0x%x\t0x%x\t0x%x\t%s\n", section_idx, + section->sh_addr, section->sh_size, offset, + seg_type == SOF_MAN_SEGMENT_TEXT ? "TEXT" : "DATA"); + + return 0; +} + +static int man_copy_elf_section(struct image *image, Elf32_Shdr *section, + struct module *module, struct sof_man_module *man_module, int idx) +{ + int ret; + + /* seek to ELF section */ + ret = fseek(module->fd, section->sh_offset, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: can't seek to section %d\n", ret); + return ret; + } + + /* write data to DRAM or ROM image */ + if (!elf_is_rom(image, section)) + return man_copy_sram(image, section, module, man_module, idx); + + return 0; +} + +static int man_get_module_manifest(struct image *image, struct module *module, + struct sof_man_module *man_module) +{ + Elf32_Shdr *section; + struct sof_man_segment_desc *segment; + struct sof_man_module sof_mod; + size_t count; + int ret, man_section_idx; + + fprintf(stdout, "Module Write: %s\n", module->elf_file); + + /* find manifest module data */ + man_section_idx = elf_find_section(image, module, ".module"); + if (man_section_idx < 0) { + return -EINVAL; + } + + fprintf(stdout, " Manifest module metadata section at index %d\n", + man_section_idx); + section = &module->section[man_section_idx]; + + /* load in manifest data */ + ret = fseek(module->fd, section->sh_offset, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: can't seek to section %d\n", ret); + return ret; + } + count = fread(&sof_mod, 1, sizeof(sof_mod), module->fd); + if (count != sizeof(sof_mod)) { + fprintf(stderr, "error: can't read section %d\n", -errno); + return -errno; + } + + /* configure man_module with sofmod data */ + memcpy(man_module->struct_id, "$AME", 4); + man_module->entry_point = sof_mod.entry_point; + memcpy(man_module->name, sof_mod.name, SOF_MAN_MOD_NAME_LEN); + memcpy(man_module->uuid, sof_mod.uuid, 16); + man_module->affinity_mask = sof_mod.affinity_mask; + man_module->type.auto_start = sof_mod.type.auto_start; + man_module->type.domain_dp = sof_mod.type.domain_dp; + man_module->type.domain_ll = sof_mod.type.domain_ll; + man_module->type.load_type = sof_mod.type.load_type; + + /* text segment */ + segment = &man_module->segment[SOF_MAN_SEGMENT_TEXT]; + segment->flags.r.contents = 1; + segment->flags.r.alloc = 1; + segment->flags.r.load = 1; + segment->flags.r.readonly = 1; + segment->flags.r.code = 1; + + /* data segment */ + segment = &man_module->segment[SOF_MAN_SEGMENT_RODATA]; + segment->flags.r.contents = 1; + segment->flags.r.alloc = 1; + segment->flags.r.load = 1; + segment->flags.r.readonly = 1; + segment->flags.r.data = 1; + segment->flags.r.type = 1; + + /* bss segment */ + segment = &man_module->segment[SOF_MAN_SEGMENT_BSS]; + segment->flags.r.alloc = 1; + segment->flags.r.type = 2; + + fprintf(stdout, " Entry point 0x%8.8x\n", man_module->entry_point); + + return 0; +} + +static int man_module_create(struct image *image, struct module *module, + struct sof_man_module *man_module) +{ + /* create module and segments */ + uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + Elf32_Shdr *section; + int i, err; + unsigned int pages; + + image->image_end = 0; + + err = man_get_module_manifest(image, module, man_module); + if (err < 0) + return err; + + /* stack size ??? convert sizes to PAGES */ + man_module->instance_bss_size = 1; + + /* max number of instances of this module ?? */ + man_module->instance_max_count = 1; + + fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize"); + + fprintf(stdout, "\n\tTEXT\t0x%x\t0x%x\t0x%x\n", + module->text_start, module->text_end, + module->text_end - module->text_start); + fprintf(stdout, "\tDATA\t0x%x\t0x%x\t0x%x\n", + module->data_start, module->data_end, + module->data_end - module->data_start); + fprintf(stdout, "\tBSS\t0x%x\t0x%x\t0x%x\n\n ", + module->bss_start, module->bss_end, + module->bss_end - module->bss_start); + + /* main module */ + /* text section is first */ + man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset = + module->foffset; + man_module->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = + module->text_start; + + /* calculates those padding 0s by the start of next segment */ + pages = module->text_file_size / MAN_PAGE_SIZE; + if (module->text_file_size % MAN_PAGE_SIZE) + pages += 1; + + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length = pages; + + /* data section */ + man_module->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr = + module->data_start; + man_module->segment[SOF_MAN_SEGMENT_RODATA].file_offset = + module->foffset + module->text_file_size; + pages = module->data_file_size / MAN_PAGE_SIZE; + if (module->data_file_size % MAN_PAGE_SIZE) + pages += 1; + + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length = pages; + + /* bss is last */ + man_module->segment[SOF_MAN_SEGMENT_BSS].file_offset = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].v_base_addr = module->bss_start; + pages = (module->bss_end - module->bss_start) / MAN_PAGE_SIZE; + if ((module->bss_end - module->bss_start) % MAN_PAGE_SIZE) + pages += 1; + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length = pages; + + fprintf(stdout, "\tNo\tAddress\t\tSize\tFile\tType\n"); + + /* find all sections and copy to corresponding segments */ + for (i = 0; i < module->hdr.e_shnum; i++) { + + section = &module->section[i]; + + /* only check valid sections */ + if (!(section->sh_flags & valid)) + continue; + + if (section->sh_size == 0) + continue; + + /* text or data section */ + if (!elf_is_rom(image, section)) + err = man_copy_elf_section(image, section, module, + man_module, i); + + if (err < 0) { + fprintf(stderr, "error: failed to write section #%d\n", i); + return err; + } + } + fprintf(stdout, "\n"); + + /* round module end upto nearest page */ + if (image->image_end % MAN_PAGE_SIZE) { + image->image_end = (image->image_end / MAN_PAGE_SIZE) + 1; + image->image_end *= MAN_PAGE_SIZE; + } + + fprintf(stdout, " Total pages text %d data %d bss %d module file limit: 0x%x\n\n", + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length, + image->image_end); + return 0; +} + +static int man_write_fw_mod(struct image *image) +{ + int count; + + /* write ROM - for VM use only */ + count = fwrite(image->rom_image, image->adsp->rom_size, 1, + image->out_rom_fd); + if (count != 1) { + fprintf(stderr, "error: failed to write rom %s %d\n", + image->out_rom_file, -errno); + return -errno; + } + fclose(image->out_rom_fd); + + /* write manifest and signed image */ + count = fwrite(image->fw_image, + image->image_end, + 1, image->out_fd); + + /* did the image write succeed ? */ + if (count != 1) { + fprintf(stderr, "error: failed to write signed firmware %s %d\n", + image->out_file, -errno); + return -errno; + } + + return 0; +} + +/* used by others */ +static int man_write_fw(struct image *image) +{ + struct sof_man_fw_desc *desc; + struct fw_image_manifest *m; + struct module *module; + struct sof_man_module *man_module; + uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; + int ret, i; + + /* init image */ + ret = man_init_image(image); + if (ret < 0) + goto err; + + /* open ROM image */ + ret = man_open_rom_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + m = image->fw_image; + desc = image->fw_image + MAN_DESC_OFFSET; + + /* create each module */ + m->desc.header.num_module_entries = image->num_modules; + for (i = 0; i < image->num_modules; i++) { + + man_module = sof_man_get_module(desc, i); + module = &image->module[i]; + + /* set module file offset */ + if (i == 0) { + module->foffset = FILE_TEXT_OFFSET; + } else { + module->foffset = image->image_end; + } + + ret = man_module_create(image, module, man_module); + if (ret < 0) + goto err; + } + + fprintf(stdout, "Firmware completing manifest\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create(image); + ri_plat_ext_data_create(image); + ri_css_hdr_create(image); + ri_cse_create(image); + + fprintf(stdout, "Firmware file size 0x%x page count %d\n", + FILE_TEXT_OFFSET - MAN_DESC_OFFSET + image->image_end, + desc->header.preload_page_count); + + /* calculate hash for each module */ + for (i = 0; i < image->num_modules; i++) { + + module = &image->module[i]; + man_module = sof_man_get_module(desc, i); + + ri_hash(image, man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset, + (man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length + + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length) * + MAN_PAGE_SIZE, man_module->hash); + } + + /* calculate hash for ADSP meta data extension - 0x480 to end */ + ri_hash(image, MAN_FW_DESC_OFFSET, image->image_end + - MAN_FW_DESC_OFFSET, m->adsp_file_ext.comp_desc[0].hash); + + /* calculate hash for platform auth data - repeated in hash 2 and 4 */ + ri_hash(image, MAN_META_EXT_OFFSET, + sizeof(struct sof_man_adsp_meta_file_ext), hash); + + /* hash values in reverse order */ + for (i = 0; i < SOF_MAN_MOD_SHA256_LEN; i++) { + m->signed_pkg.module[0].hash[i] = + m->partition_info.module[0].hash[i] = + hash[SOF_MAN_MOD_SHA256_LEN - 1 - i]; + } + + /* sign manifest */ + ret = ri_manifest_sign(image); + if (ret < 0) + goto err; + + /* write the firmware */ + ret = man_write_fw_mod(image); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest and signing completed !\n"); + return 0; + +err: + free(image->rom_image); + free(image->fw_image); + unlink(image->out_file); + unlink(image->out_rom_file); + return ret; +} + +#define ADSP_APL_DSP_ROM_BASE 0xBEFE0000 +#define ADSP_APL_DSP_ROM_SIZE 0x00002000 +#define APL_DSP_BASE_ENTRY 0xa000a000 + +#define ADSP_CNL_DSP_ROM_BASE 0xBEFE0000 +#define ADSP_CNL_DSP_ROM_SIZE 0x00002000 +#define CNL_DSP_IMR_BASE_ENTRY 0xb0038000 +#define CNL_DSP_HP_BASE_ENTRY 0xbe040000 + +/* list of supported adsp */ +const struct adsp machine_apl = { + .name = "apl", + .rom_base = ADSP_APL_DSP_ROM_BASE, + .rom_size = ADSP_APL_DSP_ROM_SIZE, + .sram_base = APL_DSP_BASE_ENTRY, + .sram_size = 0x100000, + .image_size = 0x100000, + .dram_offset = 0, + .machine_id = MACHINE_APOLLOLAKE, + .write_firmware = man_write_fw, + .man = &apl_manifest, + .base_fw_text_size_fixup = 0xa000, +}; + +const struct adsp machine_cnl = { + .name = "cnl", + .rom_base = ADSP_CNL_DSP_ROM_BASE, + .rom_size = ADSP_CNL_DSP_ROM_SIZE, + .imr_base = CNL_DSP_IMR_BASE_ENTRY, + .imr_size = 0x100000, + .sram_base = CNL_DSP_HP_BASE_ENTRY, + .sram_size = 0x100000, + .image_size = 0x100000, + .dram_offset = 0, + .machine_id = MACHINE_CANNONLAKE, + .write_firmware = man_write_fw, + .man = &cnl_manifest, +}; diff --git a/rimage/manifest.h b/rimage/manifest.h new file mode 100644 index 000000000000..ca951321f3a9 --- /dev/null +++ b/rimage/manifest.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __MANIFEST_H__ +#define __MANIFEST_H__ + +#include +#include "uapi/manifest.h" +#include "css.h" +#include "cse.h" +#include "plat_auth.h" + +#define MAN_PAGE_SIZE 4096 + +/* start offset for base FW module */ +#define FILE_TEXT_OFFSET 0x8000 + +/* + * CSE values for CNL + */ +#define MAN_CSE_PARTS 3 + + +#define MAN_CSE_HDR_OFFSET 0 +#define MAN_CSE_PADDING_SIZE 0x30 +#define MAN_EXT_PADDING 0x20 +#define MAN_DESC_OFFSET 0x2000 + +#define MAN_CSS_HDR_OFFSET \ + (MAN_CSE_HDR_OFFSET + \ + sizeof(struct CsePartitionDirHeader) + \ + MAN_CSE_PARTS * sizeof(struct CsePartitionDirEntry)) + +#define MAN_SIG_PKG_OFFSET \ + (MAN_CSS_HDR_OFFSET + \ + sizeof(struct css_header)) + +#define MAN_PART_INFO_OFFSET \ + (MAN_SIG_PKG_OFFSET + \ + sizeof(struct signed_pkg_info_ext)) + +#define MAN_META_EXT_OFFSET \ + (MAN_SIG_PKG_OFFSET + \ + sizeof(struct signed_pkg_info_ext) + \ + sizeof(struct partition_info_ext) + \ + MAN_CSE_PADDING_SIZE) + +#define MAN_FW_DESC_OFFSET \ + (MAN_META_EXT_OFFSET + \ + sizeof(struct sof_man_adsp_meta_file_ext) + \ + MAN_EXT_PADDING) + +#define MAN_DESC_PADDING_SIZE \ + (MAN_DESC_OFFSET - MAN_FW_DESC_OFFSET) + +/* + * Firmware manifest header. + */ +struct fw_image_manifest { + /* MEU tool needs these sections to be 0s */ + struct CsePartitionDirHeader cse_partition_dir_header; + struct CsePartitionDirEntry cse_partition_dir_entry[MAN_CSE_PARTS]; + struct css_header css; + struct signed_pkg_info_ext signed_pkg; + struct partition_info_ext partition_info; + uint8_t cse_padding[MAN_CSE_PADDING_SIZE]; + struct sof_man_adsp_meta_file_ext adsp_file_ext; + + /* reserved / pading at end of ext data - all 0s*/ + uint8_t reserved[MAN_EXT_PADDING]; + + /* start of the unsigned binary for MEU input must start at MAN_DESC_OFFSET */ + uint8_t padding[MAN_DESC_PADDING_SIZE]; + + struct sof_man_fw_desc desc; /* at offset MAN_DESC_OFFSET */ +} __attribute__((packed)); + +extern struct fw_image_manifest apl_manifest; +extern struct fw_image_manifest cnl_manifest; +#endif diff --git a/rimage/pkcs1_5.c b/rimage/pkcs1_5.c new file mode 100644 index 000000000000..64a4b250015b --- /dev/null +++ b/rimage/pkcs1_5.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "rimage.h" +#include "css.h" +#include "manifest.h" + +#define DEBUG_PKCS 0 + +static void bytes_swap(uint8_t *ptr, uint32_t size) +{ + uint8_t tmp; + uint32_t index; + + for (index = 0; index < (size / 2); index++) { + tmp = ptr[index]; + ptr[index] = ptr[size - 1 - index]; + ptr[size - 1 - index] = tmp; + } +} + +/* + * RSA signature of manifest. The signature is an PKCS + * #1-v1_5 of the entire manifest structure, including all + * extensions, and excluding the last 3 fields of the + * manifest header (Public Key, Exponent and Signature). +*/ + +int pkcs_sign(struct image *image, struct fw_image_manifest *man, + void *ptr1, unsigned int size1, void *ptr2, unsigned int size2) +{ + RSA *priv_rsa = NULL; + EVP_PKEY *privkey; + FILE *fp; + unsigned char digest[SHA256_DIGEST_LENGTH], mod[MAN_RSA_KEY_MODULUS_LEN]; + unsigned int siglen = MAN_RSA_SIGNATURE_LEN; + char path[256]; + int ret = -EINVAL, i; + +#if DEBUG_PKCS + fprintf(stdout, "offsets 0x%lx size 0x%x offset 0x%lx size 0x%x\n", + ptr1 - (void *)man, size1, ptr2 - (void *)man, size2); +#endif + + /* create new key */ + privkey = EVP_PKEY_new(); + if (privkey == NULL) + return -ENOMEM; + + /* load in RSA private key from PEM file */ + if (image->key_name == NULL) { + sprintf(path, "%s/otc_private_key.pem", PEM_KEY_PREFIX); + image->key_name = path; + } + + fprintf(stdout, " pkcs: signing with key %s\n", image->key_name); + fp = fopen(image->key_name, "r"); + if (fp == NULL) { + fprintf(stderr, "error: can't open file %s %d\n", path, -errno); + return -errno; + } + PEM_read_PrivateKey(fp, &privkey, NULL, NULL); + fclose(fp); + + /* validate RSA private key */ + priv_rsa = EVP_PKEY_get1_RSA(privkey); + if (RSA_check_key(priv_rsa)) { + fprintf(stdout, " pkcs: RSA private key is valid.\n"); + } else { + fprintf(stderr, "error: validating RSA private key.\n"); + return -EINVAL; + } + + /* calculate the digest */ + module_sha256_create(image); + module_sha256_update(image, ptr1, size1); + module_sha256_update(image, ptr2, size2); + module_sha256_complete(image, digest); + + fprintf(stdout, " pkcs: digest for manifest is "); + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) + fprintf(stdout, "%02x", digest[i]); + fprintf(stdout, "\n"); + + /* sign the manifest */ + ret = RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, + (unsigned char *)man->css.signature, + &siglen, priv_rsa); + if (ret < 0) + fprintf(stderr, "error: failed to sign manifest\n"); + + /* copy public key modulus and exponent to manifest */ + BN_bn2bin(priv_rsa->n, mod); + BN_bn2bin(priv_rsa->e, (unsigned char *)man->css.exponent); + + /* modulus is reveresd */ + for (i = 0; i < MAN_RSA_KEY_MODULUS_LEN; i++) + man->css.modulus[i] = mod[MAN_RSA_KEY_MODULUS_LEN - (1 + i)]; + + /* signature is reveresd, swap it */ + bytes_swap(man->css.signature, sizeof(man->css.signature)); + + EVP_PKEY_free(privkey); + return ret; +} + +int ri_manifest_sign(struct image *image) +{ + struct fw_image_manifest *man = image->fw_image; + + pkcs_sign(image, man, (void *)man + MAN_CSS_HDR_OFFSET, + sizeof(struct css_header) - + (MAN_RSA_KEY_MODULUS_LEN + MAN_RSA_KEY_EXPONENT_LEN + + MAN_RSA_SIGNATURE_LEN), + (void *)man + MAN_SIG_PKG_OFFSET, + (man->css.size - man->css.header_len) * sizeof(uint32_t)); + return 0; +} diff --git a/rimage/plat_auth.c b/rimage/plat_auth.c new file mode 100644 index 000000000000..21c7138cfbb1 --- /dev/null +++ b/rimage/plat_auth.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#include "rimage.h" +#include "manifest.h" +#include "plat_auth.h" + +void ri_adsp_meta_data_create(struct image *image) +{ + struct sof_man_adsp_meta_file_ext *meta = + image->fw_image + MAN_META_EXT_OFFSET; + + fprintf(stdout, " meta: completing ADSP manifest\n"); + + meta->comp_desc[0].limit_offset = MAN_DESC_OFFSET + image->image_end + - MAN_FW_DESC_OFFSET; + + fprintf(stdout, " meta: limit is 0x%x\n", + meta->comp_desc[0].limit_offset); + /* now hash the AdspFwBinaryDesc -> EOF */ +} + +void ri_plat_ext_data_create(struct image *image) +{ + struct partition_info_ext *part = image->fw_image + MAN_PART_INFO_OFFSET; + struct sof_man_adsp_meta_file_ext *meta = + image->fw_image + MAN_META_EXT_OFFSET; + struct sof_man_fw_desc *desc = image->fw_image + MAN_DESC_OFFSET; + + fprintf(stdout, " auth: completing authentication manifest\n"); + + part->length = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET; + part->length += MAN_PAGE_SIZE - (part->length % MAN_PAGE_SIZE); + + /* do this here atm */ + desc->header.preload_page_count = part->length / MAN_PAGE_SIZE; +} diff --git a/rimage/plat_auth.h b/rimage/plat_auth.h new file mode 100644 index 000000000000..135f2d1ce07c --- /dev/null +++ b/rimage/plat_auth.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __PLAT_AUTH_H__ +#define __PLAT_AUTH_H__ + +#include + +struct image; + +#define PLAT_AUTH_SHA256_LEN 32 +#define PLAT_AUTH_NAME_LEN 12 +#define PLAT_AUTH_PADDING 48 /* pad at end of struct */ + +#define SIGN_PKG_EXT_TYPE 15 +#define SIGN_PKG_NUM_MODULE 1 + +struct signed_pkg_info_module { + uint8_t name[PLAT_AUTH_NAME_LEN]; /* must be padded with 0 */ + uint8_t type; + uint8_t hash_algo; + uint16_t hash_size; + uint32_t meta_size; + uint8_t hash[PLAT_AUTH_SHA256_LEN]; +} __attribute__((packed)); + +struct signed_pkg_info_ext { + uint32_t ext_type; + uint32_t ext_len; + + uint8_t name[4]; + uint32_t vcn; + uint8_t bitmap[16]; + uint32_t svn; + uint8_t fw_type; + uint8_t fw_sub_type; + uint8_t reserved[14]; /* must be 0 */ + + /* variable length of modules */ + struct signed_pkg_info_module module[SIGN_PKG_NUM_MODULE]; +} __attribute__((packed)); + + +#define PART_INFO_EXT_TYPE 3 +#define PART_INFO_NUM_MODULE 1 + +struct partition_info_module { + uint8_t name[PLAT_AUTH_NAME_LEN]; /* must be padded with 0 */ + uint8_t type; + uint8_t reserved[3]; + uint32_t meta_size; + uint8_t hash[PLAT_AUTH_SHA256_LEN]; +} __attribute__((packed)); + +struct partition_info_ext { + uint32_t ext_type; + uint32_t ext_len; + + uint8_t name[4]; /* "ADSP" */ + uint32_t length; + uint8_t hash[PLAT_AUTH_SHA256_LEN]; + + uint32_t vcn; + uint32_t part_version; + uint32_t fmt_version; + uint32_t instance_id; + uint32_t part_flags; + uint8_t reserved[20]; /* must be 0 */ + + /* variable length of modules */ + struct partition_info_module module[PART_INFO_NUM_MODULE]; +} __attribute__((packed)); + + +#define PLAT_AUTH_SIZE \ + (sizeof(struct partition_info_ext) + \ + sizeof(struct signed_pkg_info_ext)) + +void ri_adsp_meta_data_create(struct image *image); +void ri_plat_ext_data_create(struct image *image); + +#endif diff --git a/rimage/rimage.c b/rimage/rimage.c new file mode 100644 index 000000000000..322820b02612 --- /dev/null +++ b/rimage/rimage.c @@ -0,0 +1,136 @@ +/* + * ELF to firmware image creator. + * + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include + +#include "rimage.h" +#include "file_format.h" +#include "manifest.h" + +static const struct adsp *machine[] = { + &machine_byt, + &machine_cht, + &machine_bsw, + &machine_hsw, + &machine_bdw, + &machine_apl, + &machine_cnl, +}; + +static void usage(char *name) +{ + fprintf(stdout, "%s:\t -m machine -o outfile -k [key] ELF files\n", name); + fprintf(stdout, "\t -v enable verbose output\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + struct image image; + const char *mach = NULL; + int opt, ret, i, elf_argc = 0; + + memset(&image, 0, sizeof(image)); + + while ((opt = getopt(argc, argv, "ho:m:vba:sk:l:")) != -1) { + switch (opt) { + case 'o': + image.out_file = optarg; + break; + case 'm': + mach = optarg; + break; + case 'v': + image.verbose = 1; + break; + case 's': + image.dump_sections = 1; + break; + case 'a': + image.abi = atoi(optarg); + break; + case 'k': + image.key_name = optarg; + break; + case 'h': + usage(argv[0]); + break; + default: + break; + } + } + + elf_argc = optind; + + /* make sure we have an outfile and machine */ + if (image.out_file == NULL || mach == NULL) + usage(argv[0]); + + + /* find machine */ + for (i = 0; i < ARRAY_SIZE(machine); i++) { + if (!strcmp(mach, machine[i]->name)) { + image.adsp = machine[i]; + goto found; + } + } + fprintf(stderr, "error: machine %s not found\n", mach); + fprintf(stderr, "error: available machines "); + for (i = 0; i < ARRAY_SIZE(machine); i++) + fprintf(stderr, "%s, ", machine[i]->name); + fprintf(stderr, "\n"); + + return -EINVAL; + +found: + + /* parse input ELF files */ + image.num_modules = argc - elf_argc; + for (i = elf_argc; i < argc; i++) { + fprintf(stdout, "\nModule Reading %s\n", argv[i]); + ret = elf_parse_module(&image, i - elf_argc, argv[i]); + if (ret < 0) + goto out; + } + + /* validate all modules */ + ret = elf_validate_modules(&image); + if (ret < 0) + goto out; + + /* open outfile for writing */ + unlink(image.out_file); + image.out_fd = fopen(image.out_file, "w"); + if (image.out_fd == NULL) { + fprintf(stderr, "error: unable to open %s for writing %d\n", + image.out_file, errno); + ret = -EINVAL; + goto out; + } + + /* process and write output */ + ret = image.adsp->write_firmware(&image); +out: + /* close files */ + if (image.out_fd) + fclose(image.out_fd); + + + return ret; +} diff --git a/rimage/rimage.h b/rimage/rimage.h new file mode 100644 index 000000000000..4e387e9ff72c --- /dev/null +++ b/rimage/rimage.h @@ -0,0 +1,170 @@ +/* + * ELF to firmware image creator. + * + * Copyright (c) 2015-2018 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __RIMAGE_H__ +#define __RIMAGE_H__ + +#include +#include +#include + +#include +#include +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#define MAX_MODULES 32 + +struct adsp; +struct manifest; +struct man_module; + +/* list of supported targets */ +enum machine_id { + MACHINE_BAYTRAIL = 0, + MACHINE_CHERRYTRAIL, + MACHINE_BRASWELL, + MACHINE_HASWELL, + MACHINE_BROADWELL, + MACHINE_APOLLOLAKE, + MACHINE_CANNONLAKE, + MACHINE_MAX +}; + +/* + * ELF module data + */ +struct module { + const char *elf_file; + FILE *fd; + + Elf32_Ehdr hdr; + Elf32_Shdr *section; + Elf32_Phdr *prg; + + uint32_t text_start; + uint32_t text_end; + uint32_t data_start; + uint32_t data_end; + uint32_t bss_start; + uint32_t bss_end; + uint32_t foffset; + + int num_sections; + int num_bss; + int fw_size; + int bss_index; + + /* sizes do not include any gaps */ + int bss_size; + int text_size; + int data_size; + + /* sizes do include gaps to nearest page */ + int bss_file_size; + int text_file_size; + int data_file_size; +}; + +/* + * Firmware image context. + */ +struct image { + + const char *out_file; + FILE *out_fd; + void *pos; + + const struct adsp *adsp; + int abi; + int verbose; + int num_modules; + struct module module[MAX_MODULES]; + uint32_t image_end;/* module end, equal to output image size */ + int dump_sections; + + /* SHA 256 */ + const char *key_name; + EVP_MD_CTX *mdctx; + const EVP_MD *md; + + /* file IO */ + void *fw_image; + void *rom_image; + FILE *out_rom_fd; + FILE *out_man_fd; + FILE *out_unsigned_fd; + char out_rom_file[256]; + char out_man_file[256]; + char out_unsigned_file[256]; +}; + +/* + * Audio DSP descriptor and operations. + */ +struct adsp { + const char *name; + uint32_t iram_base; + uint32_t iram_size; + uint32_t dram_base; + uint32_t dram_size; + uint32_t sram_base; + uint32_t sram_size; + uint32_t host_iram_offset; + uint32_t host_dram_offset; + uint32_t rom_base; + uint32_t rom_size; + uint32_t imr_base; + uint32_t imr_size; + + uint32_t image_size; + uint32_t dram_offset; + + enum machine_id machine_id; + int (*write_firmware)(struct image *image); + struct fw_image_manifest *man; + + /* fixups */ + uint32_t base_fw_text_size_fixup; /* added to BASEFW text size */ +}; + +void module_sha256_create(struct image *image); +void module_sha256_update(struct image *image, uint8_t *data, size_t bytes); +void module_sha256_complete(struct image *image, uint8_t *hash); +int ri_manifest_sign(struct image *image); +void ri_hash(struct image *image, unsigned offset, unsigned size, uint8_t *hash); + +int pkcs_sign(struct image *image, struct fw_image_manifest *man, + void *ptr1, unsigned size1, void *ptr2, unsigned size2); + +int elf_parse_module(struct image *image, int module_index, const char *name); +void elf_free_module(struct image *image, int module_index); +int elf_is_rom(struct image *image, Elf32_Shdr *section); +int elf_validate_modules(struct image *image); +int elf_find_section(struct image *image, struct module *module, + const char *name); +int elf_validate_section(struct image *image, struct module *module, + Elf32_Shdr *section); + +/* supported machines */ +extern const struct adsp machine_byt; +extern const struct adsp machine_cht; +extern const struct adsp machine_bsw; +extern const struct adsp machine_hsw; +extern const struct adsp machine_bdw; +extern const struct adsp machine_apl; +extern const struct adsp machine_cnl; + +#endif