From 81eba29a2fcd3a28e0d61aaf448290b74002441c Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Mon, 4 Jun 2018 12:03:42 +0100 Subject: [PATCH] rimage: add support for automatic MEU signing This patch allows rimage to sign FW binaries using MEU tool. Paths to MEU and private key have to be provided during config step. Signed-off-by: Tomasz Lauda --- rimage/manifest.c | 172 +++++++++++++++++++++++++++++++++++---------- rimage/plat_auth.c | 7 +- rimage/plat_auth.h | 3 +- rimage/rimage.c | 10 ++- rimage/rimage.h | 3 +- 5 files changed, 149 insertions(+), 46 deletions(-) diff --git a/rimage/manifest.c b/rimage/manifest.c index 257aa0d3a..b758717b5 100644 --- a/rimage/manifest.c +++ b/rimage/manifest.c @@ -539,12 +539,13 @@ static int man_module_create_reloc(struct image *image, struct module *module, return 0; } -static int man_write_unsigned_mod(struct image *image) +static int man_write_unsigned_mod(struct image *image, int meta_start_offset, + int meta_end_offset) { int count; /* write metadata file for unsigned FW */ - count = fwrite(image->fw_image + MAN_META_EXT_OFFSET, + count = fwrite(image->fw_image + meta_start_offset, sizeof(struct sof_man_adsp_meta_file_ext), 1, image->out_man_fd); @@ -557,8 +558,8 @@ static int man_write_unsigned_mod(struct image *image) fclose(image->out_man_fd); /* now prepare the unsigned rimage */ - count = fwrite(image->fw_image + MAN_FW_DESC_OFFSET, - image->image_end - MAN_FW_DESC_OFFSET, + count = fwrite(image->fw_image + meta_end_offset, + image->image_end - meta_end_offset, 1, image->out_unsigned_fd); /* did the unsigned FW write succeed ? */ @@ -601,13 +602,59 @@ static int man_write_fw_mod(struct image *image) return 0; } +static int man_create_modules(struct image *image, struct sof_man_fw_desc *desc) +{ + struct module *module; + struct sof_man_module *man_module; + int err; + int i; + + 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; + + if (image->reloc) + err = man_module_create_reloc(image, module, + man_module); + else + err = man_module_create(image, module, man_module); + + if (err < 0) + return err; + } + + return 0; +} + +static int man_hash_modules(struct image *image, struct sof_man_fw_desc *desc) +{ + struct sof_man_module *man_module; + int i; + + for (i = 0; i < image->num_modules; 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); + } + + 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; @@ -637,31 +684,13 @@ static int man_write_fw(struct image *image) /* 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; - } - - if (image->reloc) - ret = man_module_create_reloc(image, module, - man_module); - else - ret = man_module_create(image, module, man_module); - if (ret < 0) - goto err; - } + man_create_modules(image, desc); fprintf(stdout, "Firmware completing manifest\n"); /* create structures from end of file to start of file */ - ri_adsp_meta_data_create(image); + ri_adsp_meta_data_create(image, MAN_META_EXT_OFFSET, + MAN_FW_DESC_OFFSET); ri_plat_ext_data_create(image); ri_css_hdr_create(image); ri_cse_create(image); @@ -671,16 +700,7 @@ static int man_write_fw(struct image *image) 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); - } + man_hash_modules(image, desc); /* calculate hash for ADSP meta data extension - 0x480 to end */ ri_hash(image, MAN_FW_DESC_OFFSET, image->image_end @@ -708,7 +728,8 @@ static int man_write_fw(struct image *image) goto err; /* write the unsigned files*/ - ret = man_write_unsigned_mod(image); + ret = man_write_unsigned_mod(image, MAN_META_EXT_OFFSET, + MAN_FW_DESC_OFFSET); if (ret < 0) goto err; @@ -723,6 +744,79 @@ err: return ret; } +/* used to sign with MEU */ +static int man_write_fw_meu(struct image *image) +{ + const int meta_start_offset = image->meu_offset - + sizeof(struct sof_man_adsp_meta_file_ext) - MAN_EXT_PADDING; + struct sof_man_adsp_meta_file_ext *meta; + struct sof_man_fw_desc *desc; + uint32_t preload_size; + int ret; + + /* allocate image */ + image->fw_image = calloc(image->adsp->image_size, 1); + if (image->fw_image == NULL) { + ret = -ENOMEM; + goto err; + } + + /* open unsigned firmware */ + ret = man_open_unsigned_file(image); + if (ret < 0) + goto err; + + /* create the manifest */ + ret = man_open_manifest_file(image); + if (ret < 0) + goto err; + + /* create the module */ + meta = image->fw_image + meta_start_offset; + desc = image->fw_image + MAN_DESC_OFFSET; + + /* copy data */ + memcpy(meta, &image->adsp->man->adsp_file_ext, + sizeof(struct sof_man_adsp_meta_file_ext)); + memcpy(desc, &image->adsp->man->desc, + sizeof(struct sof_man_fw_desc)); + + /* create each module */ + desc->header.num_module_entries = image->num_modules; + man_create_modules(image, desc); + + fprintf(stdout, "Firmware completing manifest\n"); + + /* create structures from end of file to start of file */ + ri_adsp_meta_data_create(image, meta_start_offset, image->meu_offset); + + /* write preload page count */ + preload_size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET; + preload_size += MAN_PAGE_SIZE - (preload_size % MAN_PAGE_SIZE); + desc->header.preload_page_count = preload_size / MAN_PAGE_SIZE; + + /* calculate hash for each module */ + man_hash_modules(image, desc); + + /* calculate hash for ADSP meta data extension */ + ri_hash(image, image->meu_offset, image->image_end - + image->meu_offset, meta->comp_desc[0].hash); + + /* write the unsigned files */ + ret = man_write_unsigned_mod(image, meta_start_offset, + image->meu_offset); + if (ret < 0) + goto err; + + fprintf(stdout, "Firmware manifest completed!\n"); + return 0; + +err: + free(image->fw_image); + unlink(image->out_file); + return ret; +} + #define ADSP_APL_DSP_ROM_BASE 0xBEFE0000 #define ADSP_APL_DSP_ROM_SIZE 0x00002000 #define APL_DSP_BASE_ENTRY 0xa000a000 @@ -743,6 +837,7 @@ const struct adsp machine_apl = { .dram_offset = 0, .machine_id = MACHINE_APOLLOLAKE, .write_firmware = man_write_fw, + .write_firmware_meu = man_write_fw_meu, .man = &apl_manifest, }; @@ -758,5 +853,6 @@ const struct adsp machine_cnl = { .dram_offset = 0, .machine_id = MACHINE_CANNONLAKE, .write_firmware = man_write_fw, + .write_firmware_meu = man_write_fw_meu, .man = &cnl_manifest, }; diff --git a/rimage/plat_auth.c b/rimage/plat_auth.c index 21c7138cf..2fd62aa0a 100644 --- a/rimage/plat_auth.c +++ b/rimage/plat_auth.c @@ -18,15 +18,16 @@ #include "manifest.h" #include "plat_auth.h" -void ri_adsp_meta_data_create(struct image *image) +void ri_adsp_meta_data_create(struct image *image, int meta_start_offset, + int meta_end_offset) { struct sof_man_adsp_meta_file_ext *meta = - image->fw_image + MAN_META_EXT_OFFSET; + image->fw_image + meta_start_offset; fprintf(stdout, " meta: completing ADSP manifest\n"); meta->comp_desc[0].limit_offset = MAN_DESC_OFFSET + image->image_end - - MAN_FW_DESC_OFFSET; + - meta_end_offset; fprintf(stdout, " meta: limit is 0x%x\n", meta->comp_desc[0].limit_offset); diff --git a/rimage/plat_auth.h b/rimage/plat_auth.h index 135f2d1ce..253a78bf4 100644 --- a/rimage/plat_auth.h +++ b/rimage/plat_auth.h @@ -86,7 +86,8 @@ struct partition_info_ext { (sizeof(struct partition_info_ext) + \ sizeof(struct signed_pkg_info_ext)) -void ri_adsp_meta_data_create(struct image *image); +void ri_adsp_meta_data_create(struct image *image, int meta_start_offset, + int meta_end_offset); void ri_plat_ext_data_create(struct image *image); #endif diff --git a/rimage/rimage.c b/rimage/rimage.c index cc0a6101c..e8b9dc8e7 100644 --- a/rimage/rimage.c +++ b/rimage/rimage.c @@ -39,6 +39,7 @@ static void usage(char *name) name); fprintf(stdout, "\t -v enable verbose output\n"); fprintf(stdout, "\t -r enable relocatable ELF files\n"); + fprintf(stdout, "\t -s MEU signing offset\n"); exit(0); } @@ -50,7 +51,7 @@ int main(int argc, char *argv[]) memset(&image, 0, sizeof(image)); - while ((opt = getopt(argc, argv, "ho:m:vba:sk:l:r")) != -1) { + while ((opt = getopt(argc, argv, "ho:m:vba:s:k:l:r")) != -1) { switch (opt) { case 'o': image.out_file = optarg; @@ -62,7 +63,7 @@ int main(int argc, char *argv[]) image.verbose = 1; break; case 's': - image.dump_sections = 1; + image.meu_offset = atoi(optarg); break; case 'a': image.abi = atoi(optarg); @@ -130,7 +131,10 @@ found: } /* process and write output */ - ret = image.adsp->write_firmware(&image); + if (image.meu_offset) + ret = image.adsp->write_firmware_meu(&image); + else + ret = image.adsp->write_firmware(&image); out: /* close files */ if (image.out_fd) diff --git a/rimage/rimage.h b/rimage/rimage.h index 888e7e8e7..3398ece5c 100644 --- a/rimage/rimage.h +++ b/rimage/rimage.h @@ -99,7 +99,7 @@ struct image { int num_modules; struct module module[MAX_MODULES]; uint32_t image_end;/* module end, equal to output image size */ - int dump_sections; + int meu_offset; /* SHA 256 */ const char *key_name; @@ -140,6 +140,7 @@ struct adsp { enum machine_id machine_id; int (*write_firmware)(struct image *image); + int (*write_firmware_meu)(struct image *image); struct fw_image_manifest *man; };