| /* |
| * 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 <liam.r.girdwood@linux.intel.com> |
| * Keyon Jie <yang.jie@linux.intel.com> |
| */ |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <time.h> |
| #include <sys/time.h> |
| |
| #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_unsigned_file(struct image *image) |
| { |
| sprintf(image->out_unsigned_file, "%s.uns", image->out_file); |
| unlink(image->out_unsigned_file); |
| |
| /* open unsigned FW outfile for writing */ |
| image->out_unsigned_fd = fopen(image->out_unsigned_file, "w"); |
| if (image->out_unsigned_fd == NULL) { |
| fprintf(stderr, "error: unable to open %s for writing %d\n", |
| image->out_unsigned_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_fixup_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\t\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_manifest 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 */ |
| /* module built using xcc has preceding bytes */ |
| if (section->sh_size > sizeof(sof_mod)) |
| ret = fseek(module->fd, |
| section->sh_offset + XCC_MOD_OFFSET, SEEK_SET); |
| else |
| 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.module.entry_point; |
| memcpy(man_module->name, sof_mod.module.name, SOF_MAN_MOD_NAME_LEN); |
| memcpy(man_module->uuid, sof_mod.module.uuid, 16); |
| man_module->affinity_mask = sof_mod.module.affinity_mask; |
| man_module->type.auto_start = sof_mod.module.type.auto_start; |
| man_module->type.domain_dp = sof_mod.module.type.domain_dp; |
| man_module->type.domain_ll = sof_mod.module.type.domain_ll; |
| man_module->type.load_type = sof_mod.module.type.load_type; |
| |
| /* read out text_fixup_size from memory mapping */ |
| module->text_fixup_size = sof_mod.text_size; |
| |
| /* 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 inline const char *segment_name(int i) |
| { |
| switch (i) { |
| case SOF_MAN_SEGMENT_TEXT: |
| return "TEXT"; |
| case SOF_MAN_SEGMENT_RODATA: |
| return "DATA"; |
| case SOF_MAN_SEGMENT_BSS: |
| return "BSS"; |
| default: |
| return "NONE"; |
| } |
| } |
| |
| /* make sure no segments collide */ |
| static int man_module_validate(struct sof_man_module *man_module) |
| { |
| uint32_t istart, iend; |
| uint32_t jstart, jend; |
| int i, j; |
| |
| for (i = 0; i < 3; i++) { |
| |
| istart = man_module->segment[i].v_base_addr; |
| iend = istart + man_module->segment[i].flags.r.length * |
| MAN_PAGE_SIZE; |
| |
| for (j = 0; j < 3; j++) { |
| |
| /* don't validate segment against itself */ |
| if (i == j) |
| continue; |
| |
| jstart = man_module->segment[j].v_base_addr; |
| jend = jstart + man_module->segment[j].flags.r.length * |
| MAN_PAGE_SIZE; |
| |
| if (jstart > istart && jstart < iend) |
| goto err; |
| |
| if (jend > istart && jend < iend) |
| goto err; |
| } |
| } |
| |
| /* success, no overlapping segments */ |
| return 0; |
| |
| err: |
| fprintf(stderr, "error: segment %s [0x%8.8x:0x%8.8x] overlaps", |
| segment_name(i), istart, iend); |
| fprintf(stderr, " with %s [0x%8.8x:0x%8.8x]\n", |
| segment_name(j), jstart, jend); |
| return -EINVAL; |
| } |
| |
| 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%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); |
| |
| /* 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; |
| |
| if (module->text_fixup_size == 0) |
| module->text_fixup_size = module->text_file_size; |
| |
| /* check if text_file_size is bigger then text_fixup_size */ |
| if (module->text_file_size > module->text_fixup_size) { |
| fprintf(stderr, "error: too small text size assigned!\n"); |
| return -EINVAL; |
| } |
| |
| 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_fixup_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; |
| if (pages == 0) { |
| man_module->segment[SOF_MAN_SEGMENT_BSS].flags.ul = 0; |
| man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.type = |
| SOF_MAN_SEGMENT_EMPTY; |
| } |
| |
| fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); |
| |
| if (man_module_validate(man_module) < 0) |
| return -EINVAL; |
| |
| /* 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_module_create_reloc(struct image *image, struct module *module, |
| struct sof_man_module *man_module) |
| { |
| /* create module and segments */ |
| int err; |
| unsigned int pages; |
| void *buffer = image->fw_image + module->foffset; |
| size_t count; |
| |
| 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%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); |
| |
| /* 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 = 0; |
| man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length = 0; |
| |
| /* data section */ |
| man_module->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr = 0; |
| man_module->segment[SOF_MAN_SEGMENT_RODATA].file_offset = |
| module->foffset; |
| 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 = 0; |
| man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length = 0; |
| |
| fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); |
| |
| /* seek to beginning of file */ |
| err = fseek(module->fd, 0, SEEK_SET); |
| if (err < 0) { |
| fprintf(stderr, "error: can't seek to section %d\n", err); |
| return err; |
| } |
| |
| count = fread(buffer, 1, module->file_size, module->fd); |
| if (count != module->file_size) { |
| fprintf(stderr, "error: can't read section %d\n", -errno); |
| return -errno; |
| } |
| |
| fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%x\t%s\n", 0, |
| 0, module->file_size, 0, "DATA"); |
| |
| fprintf(stdout, "\n"); |
| image->image_end = module->foffset + module->file_size; |
| |
| /* round module end up to 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_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 + meta_start_offset, |
| sizeof(struct sof_man_adsp_meta_file_ext), 1, |
| image->out_man_fd); |
| |
| /* did the metadata/manifest write succeed ? */ |
| if (count != 1) { |
| fprintf(stderr, "error: failed to write meta %s %d\n", |
| image->out_man_file, -errno); |
| return -errno; |
| } |
| fclose(image->out_man_fd); |
| |
| /* now prepare the unsigned rimage */ |
| 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 ? */ |
| if (count != 1) { |
| fprintf(stderr, "error: failed to write firmware %s %d\n", |
| image->out_unsigned_file, -errno); |
| return -errno; |
| } |
| fclose(image->out_unsigned_fd); |
| |
| 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; |
| } |
| |
| 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; |
| 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; |
| |
| /* 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 */ |
| m = image->fw_image; |
| desc = image->fw_image + MAN_DESC_OFFSET; |
| |
| /* create each module */ |
| m->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, MAN_META_EXT_OFFSET, |
| MAN_FW_DESC_OFFSET); |
| 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 */ |
| 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 |
| - 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; |
| |
| /* write the unsigned files*/ |
| ret = man_write_unsigned_mod(image, MAN_META_EXT_OFFSET, |
| MAN_FW_DESC_OFFSET); |
| 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; |
| } |
| |
| /* 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 |
| |
| #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, |
| .write_firmware_meu = man_write_fw_meu, |
| .man = &apl_manifest, |
| }; |
| |
| 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, |
| .write_firmware_meu = man_write_fw_meu, |
| .man = &cnl_manifest, |
| }; |