// SPDX-License-Identifier: BSD-3-Clause // // Copyright(c) 2018 Intel Corporation. All rights reserved. // // Author: Liam Girdwood // Keyon Jie // Janusz Jankowski #include #include #include #include #include #include #include #include #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) { uint32_t size; sprintf(image->out_rom_file, "%s.rom", image->out_file); unlink(image->out_rom_file); size = image->adsp->mem_zones[SOF_FW_BLK_TYPE_ROM].size; /* allocate ROM image */ image->rom_image = calloc(size, 1); if (!image->rom_image) return -ENOMEM; /* open ROM outfile for writing */ image->out_rom_fd = fopen(image->out_rom_file, "wb"); if (!image->out_rom_fd) { fprintf(stderr, "error: unable to open %s for writing %d\n", image->out_rom_file, errno); return -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, "wb"); if (!image->out_unsigned_fd) { fprintf(stderr, "error: unable to open %s for writing %d\n", image->out_unsigned_file, errno); return -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, "wb"); if (!image->out_man_fd) { fprintf(stderr, "error: unable to open %s for writing %d\n", image->out_man_file, errno); return -errno; } return 0; } static int man_init_image_v1_5(struct image *image) { /* allocate image and copy template manifest */ image->fw_image = calloc(image->adsp->image_size, 1); if (!image->fw_image) return -ENOMEM; memcpy(image->fw_image, image->adsp->man_v1_5, sizeof(struct fw_image_manifest_v1_5)); return 0; } static int man_init_image_v1_5_sue(struct image *image) { /* allocate image and copy template manifest */ image->fw_image = calloc(image->adsp->image_size, 1); if (!image->fw_image) return -ENOMEM; /* copy 1.5 sue manifest */ memcpy(image->fw_image + MAN_DESC_OFFSET_V1_5_SUE, image->adsp->man_v1_5_sue, sizeof(struct fw_image_manifest_v1_5_sue)); return 0; } static int man_init_image_v1_8(struct image *image) { /* allocate image and copy template manifest */ image->fw_image = calloc(image->adsp->image_size, 1); if (!image->fw_image) return -ENOMEM; memcpy(image->fw_image, image->adsp->man_v1_8, sizeof(struct fw_image_manifest_v1_8)); 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->vaddr, file_offset = 0; if (section->type == SHT_PROGBITS) { if (section->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->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->size; int seg_type = -1; void *buffer = image->fw_image + offset; size_t count; switch (section->type) { case SHT_PROGBITS: /* text or data */ if (section->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; /* FALLTHRU */ 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->size, module->fd); if (count != section->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->vaddr, section->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->off, 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->size > sizeof(sof_mod)) ret = fseek(module->fd, section->off + image->xcc_mod_offset, SEEK_SET); else ret = fseek(module->fd, section->off, 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.shnum; i++) { section = &module->section[i]; /* only check valid sections */ if (!(section->flags & valid)) continue; if (section->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"); /* no need to update end for exec headers */ if (module->exec_header) { image->image_end = FILE_TEXT_OFFSET_V1_5_SUE; goto out; } /* 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; } out: 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, size_t ext_file_size) { int count; /* write metadata file for unsigned FW */ count = fwrite(image->fw_image + meta_start_offset, ext_file_size, 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 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, int file_text_offset) { struct module *module; struct sof_man_module *man_module; int err; int i = 0, offset = 0; /* if first module is executable then write before manifest */ if (image->adsp->exec_boot_ldr) { man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(0); module = &image->module[0]; fprintf(stdout, "Module: %s used as executable header\n", module->elf_file); module->exec_header = 1; /* set module file offset */ module->foffset = 0; err = man_module_create(image, module, man_module); if (err < 0) return err; /* setup man_modules for missing exec loader module */ i = 1; offset = 1; } for (; i < image->num_modules; i++) { man_module = (void *)desc + SOF_MAN_MODULE_OFFSET(i - offset); module = &image->module[i]; 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 = (void *)desc + SOF_MAN_MODULE_OFFSET(i); if (image->adsp->exec_boot_ldr && i == 0) { fprintf(stdout, " module: no need to hash %s\n as its exec header\n", man_module->name); continue; } ri_sha256(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_v1_5(struct image *image) { struct sof_man_fw_desc *desc; struct fw_image_manifest_v1_5 *m; int ret; /* init image */ ret = man_init_image_v1_5(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_V1_5; /* create each module */ m->desc.header.num_module_entries = image->num_modules; man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_5); fprintf(stdout, "Firmware completing manifest v1.5\n"); /* create structures from end of file to start of file */ ri_css_v1_5_hdr_create(image); fprintf(stdout, "Firmware file size 0x%x page count %d\n", FILE_TEXT_OFFSET_V1_5 - MAN_DESC_OFFSET_V1_5 + image->image_end, desc->header.preload_page_count); /* calculate hash for each module */ man_hash_modules(image, desc); /* sign manifest */ ret = ri_manifest_sign_v1_5(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_V1_5, MAN_FW_DESC_OFFSET_V1_5, sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); 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 by others */ static int man_write_fw_v1_5_sue(struct image *image) { struct fw_image_manifest_v1_5_sue *m; uint32_t preload_size; int ret; /* init image */ ret = man_init_image_v1_5_sue(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 + MAN_DESC_OFFSET_V1_5_SUE; /* create each module - subtract the boot loader exec header */ m->desc.header.num_module_entries = image->num_modules - 1; man_create_modules(image, &m->desc, FILE_TEXT_OFFSET_V1_5_SUE); fprintf(stdout, "Firmware completing manifest v1.5\n"); /* write preload page count */ preload_size = image->image_end - MAN_DESC_OFFSET_V1_5_SUE; preload_size += MAN_PAGE_SIZE - (preload_size % MAN_PAGE_SIZE); m->desc.header.preload_page_count = preload_size / MAN_PAGE_SIZE; fprintf(stdout, "Firmware file size 0x%x page count %d\n", FILE_TEXT_OFFSET_V1_5_SUE - MAN_DESC_OFFSET_V1_5_SUE + image->image_end, m->desc.header.preload_page_count); /* calculate hash for each module */ man_hash_modules(image, &m->desc); /* 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->fw_image); unlink(image->out_file); return ret; } /* used by others */ static int man_write_fw_v1_8(struct image *image) { struct sof_man_fw_desc *desc; struct fw_image_manifest_v1_8 *m; uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; int ret, i; /* init image */ ret = man_init_image_v1_8(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_V1_8; /* create each module */ m->desc.header.num_module_entries = image->num_modules; man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); fprintf(stdout, "Firmware completing manifest v1.8\n"); /* create structures from end of file to start of file */ ri_adsp_meta_data_create_v1_8(image, MAN_META_EXT_OFFSET_V1_8, MAN_FW_DESC_OFFSET_V1_8); ri_plat_ext_data_create(image); ri_css_v1_8_hdr_create(image); ri_cse_create(image); fprintf(stdout, "Firmware file size 0x%x page count %d\n", FILE_TEXT_OFFSET_V1_8 - MAN_DESC_OFFSET_V1_8 + 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_sha256(image, MAN_FW_DESC_OFFSET_V1_8, image->image_end - MAN_FW_DESC_OFFSET_V1_8, m->adsp_file_ext.comp_desc[0].hash); /* calculate hash for platform auth data - repeated in hash 2 and 4 */ ri_sha256(image, MAN_META_EXT_OFFSET_V1_8, sizeof(struct sof_man_adsp_meta_file_ext_v1_8), 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_v1_8(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_V1_8, MAN_FW_DESC_OFFSET_V1_8, sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); 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_v1_5(struct image *image) { const int meta_start_offset = image->meu_offset - sizeof(struct sof_man_adsp_meta_file_ext_v1_8) - MAN_EXT_PADDING; struct sof_man_adsp_meta_file_ext_v1_8 *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) { 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_V1_5; /* copy data */ memcpy(desc, &image->adsp->man_v1_5->desc, sizeof(struct sof_man_fw_desc)); /* create each module */ desc->header.num_module_entries = image->num_modules; man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_5); fprintf(stdout, "Firmware completing manifest v1.5\n"); /* create structures from end of file to start of file */ ri_adsp_meta_data_create_v1_8(image, meta_start_offset, image->meu_offset); /* write preload page count */ preload_size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_5; 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_sha256(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, sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); if (ret < 0) goto err; fprintf(stdout, "Firmware manifest completed!\n"); return 0; err: free(image->fw_image); unlink(image->out_file); return ret; } /* used to sign with MEU */ static int man_write_fw_meu_v1_8(struct image *image) { const int meta_start_offset = image->meu_offset - sizeof(struct sof_man_adsp_meta_file_ext_v1_8) - MAN_EXT_PADDING; struct sof_man_adsp_meta_file_ext_v1_8 *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) { 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_V1_8; /* copy data */ memcpy(meta, &image->adsp->man_v1_8->adsp_file_ext, sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); memcpy(desc, &image->adsp->man_v1_8->desc, sizeof(struct sof_man_fw_desc)); /* create each module */ desc->header.num_module_entries = image->num_modules; man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); fprintf(stdout, "Firmware completing manifest v1.8\n"); /* create structures from end of file to start of file */ ri_adsp_meta_data_create_v1_8(image, meta_start_offset, image->meu_offset); /* write preload page count */ preload_size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_8; 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_sha256(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, sizeof(struct sof_man_adsp_meta_file_ext_v1_8)); if (ret < 0) goto err; fprintf(stdout, "Firmware manifest completed!\n"); return 0; err: free(image->fw_image); unlink(image->out_file); return ret; } /* used to sign with MEU */ static int man_write_fw_meu_v2_5(struct image *image) { const int meta_start_offset = image->meu_offset - sizeof(struct sof_man_adsp_meta_file_ext_v2_5) - MAN_EXT_PADDING; struct sof_man_adsp_meta_file_ext_v2_5 *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) { 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_V1_8; /* copy data */ memcpy(meta, &image->adsp->man_v2_5->adsp_file_ext, sizeof(struct sof_man_adsp_meta_file_ext_v2_5)); memcpy(desc, &image->adsp->man_v2_5->desc, sizeof(struct sof_man_fw_desc)); /* create each module */ desc->header.num_module_entries = image->num_modules; man_create_modules(image, desc, FILE_TEXT_OFFSET_V1_8); fprintf(stdout, "Firmware completing manifest v2.5\n"); /* create structures from end of file to start of file */ ri_adsp_meta_data_create_v2_5(image, meta_start_offset, image->meu_offset); /* write preload page count */ preload_size = meta->comp_desc[0].limit_offset - MAN_DESC_OFFSET_V1_8; 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_sha384(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, sizeof(struct sof_man_adsp_meta_file_ext_v2_5)); 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_KBL_DSP_ROM_BASE 0xBEFE0000 #define ADSP_KBL_DSP_ROM_SIZE 0x00002000 #define KBL_DSP_BASE_ENTRY 0xa000a000 #define ADSP_SKL_DSP_ROM_BASE 0xBEFE0000 #define ADSP_SKL_DSP_ROM_SIZE 0x00002000 #define SKL_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 #define ADSP_SUE_DSP_ROM_BASE 0xBEFE0000 #define ADSP_SUE_DSP_ROM_SIZE 0x00002000 #define SUE_DSP_IMR_BASE_ENTRY 0xb0038000 #define SUE_DSP_HP_BASE_ENTRY 0xbe000000 #define ADSP_ICL_DSP_ROM_BASE 0xBEFE0000 #define ADSP_ICL_DSP_ROM_SIZE 0x00002000 #define ICL_DSP_IMR_BASE_ENTRY 0xb0038000 #define ICL_DSP_HP_BASE_ENTRY 0xbe040000 #define ADSP_TGL_DSP_ROM_BASE 0x9F180000 #define ADSP_TGL_DSP_ROM_SIZE 0x00002000 #define TGL_DSP_IMR_BASE_ENTRY 0xb0038000 #define TGL_DSP_HP_BASE_ENTRY 0xbe040000 /* list of supported adsp */ const struct adsp machine_apl = { .name = "apl", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_APL_DSP_ROM_BASE, .size = ADSP_APL_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = APL_DSP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_APOLLOLAKE, .write_firmware = man_write_fw_v1_8, .write_firmware_meu = man_write_fw_meu_v1_8, .man_v1_8 = &apl_manifest, }; const struct adsp machine_kbl = { .name = "kbl", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_KBL_DSP_ROM_BASE, .size = ADSP_KBL_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = KBL_DSP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_KABYLAKE, .write_firmware = man_write_fw_v1_5, .write_firmware_meu = man_write_fw_meu_v1_5, .man_v1_5 = &kbl_manifest, }; const struct adsp machine_skl = { .name = "skl", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_SKL_DSP_ROM_BASE, .size = ADSP_SKL_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = SKL_DSP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_SKYLAKE, .write_firmware = man_write_fw_v1_5, .write_firmware_meu = man_write_fw_meu_v1_5, .man_v1_5 = &kbl_manifest, }; const struct adsp machine_cnl = { .name = "cnl", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_CNL_DSP_ROM_BASE, .size = ADSP_CNL_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_IMR] = { .base = CNL_DSP_IMR_BASE_ENTRY, .size = 0x100000, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = CNL_DSP_HP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_CANNONLAKE, .write_firmware = man_write_fw_v1_8, .write_firmware_meu = man_write_fw_meu_v1_8, .man_v1_8 = &cnl_manifest, }; const struct adsp machine_icl = { .name = "icl", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_ICL_DSP_ROM_BASE, .size = ADSP_ICL_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_IMR] = { .base = ICL_DSP_IMR_BASE_ENTRY, .size = 0x100000, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = ICL_DSP_HP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_ICELAKE, .write_firmware = man_write_fw_v1_8, .write_firmware_meu = man_write_fw_meu_v1_8, .man_v1_8 = &cnl_manifest, // use the same as CNL }; const struct adsp machine_jsl = { .name = "jsl", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_ICL_DSP_ROM_BASE, .size = ADSP_ICL_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_IMR] = { .base = ICL_DSP_IMR_BASE_ENTRY, .size = 0x100000, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = ICL_DSP_HP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_ICELAKE, .write_firmware = man_write_fw_v1_8, .write_firmware_meu = man_write_fw_meu_v1_8, .man_v1_8 = &cnl_manifest, // use the same as CNL }; const struct adsp machine_tgl = { .name = "tgl", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_TGL_DSP_ROM_BASE, .size = ADSP_TGL_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_IMR] = { .base = TGL_DSP_IMR_BASE_ENTRY, .size = 0x100000, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = TGL_DSP_HP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_TIGERLAKE, .write_firmware = NULL, /* not yet implemented */ .write_firmware_meu = man_write_fw_meu_v2_5, .man_v2_5 = &tgl_manifest, }; const struct adsp machine_sue = { .name = "sue", .mem_zones = { [SOF_FW_BLK_TYPE_ROM] = { .base = ADSP_SUE_DSP_ROM_BASE, .size = ADSP_SUE_DSP_ROM_SIZE, }, [SOF_FW_BLK_TYPE_IMR] = { .base = SUE_DSP_IMR_BASE_ENTRY, .size = 0x100000, }, [SOF_FW_BLK_TYPE_SRAM] = { .base = SUE_DSP_HP_BASE_ENTRY, .size = 0x100000, }, }, .image_size = 0x100000, .dram_offset = 0, .machine_id = MACHINE_SUECREEK, .write_firmware = man_write_fw_v1_5_sue, .write_firmware_meu = man_write_fw_v1_5_sue, .man_v1_5_sue = &sue_manifest, .exec_boot_ldr = 1, };