Kangheui Won has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/59866 )
Change subject: amdfwtool: Add options to separate signed firmwares ......................................................................
amdfwtool: Add options to separate signed firmwares
Add support for separating signed firmwares into another file.
If sig_opt in file header is 1 it means that the firmware is signed by AMD and will be verified by the PSP. If we put them outside FW_MAIN_[AB] we can skip vboot verification on them, improving overall verification time.
BUG=b:206909680 TEST=build amdfwtool
Signed-off-by: Kangheui Won khwon@chromium.org Change-Id: I9f3610a7002b2a9c70946b083b0b3be6934200b0 --- M util/amdfwtool/amdfwtool.c M util/amdfwtool/amdfwtool.h 2 files changed, 170 insertions(+), 8 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/66/59866/1
diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c index ee360f0..856aa6f 100644 --- a/util/amdfwtool/amdfwtool.c +++ b/util/amdfwtool/amdfwtool.c @@ -630,6 +630,117 @@ } }
+static void process_signed_psp_firmwares(const char *signed_rom, + amd_fw_entry *fw_table, + uint64_t signed_start_addr) +{ + unsigned int i; + int fd; + int signed_rom_fd; + ssize_t bytes; + uint8_t *buf; + struct amd_fw_header header; + struct stat fd_stat; + + signed_rom_fd = open(signed_rom , O_RDWR | O_CREAT | O_TRUNC, 0666); + if (signed_rom_fd < 0) { + fprintf(stderr, "Error opening file: %s: %s\n", + signed_rom, strerror(errno)); + return; + } + + for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { + if (!(fw_table[i].filename)) + continue; + + memset(&header, 0, sizeof(header)); + + fd = open(fw_table[i].filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Error opening file: %s: %s\n", + fw_table[i].filename, strerror(errno)); + continue; + } + + if (fstat(fd, &fd_stat)) { + fprintf(stderr, "fstat error: %s\n", strerror(errno)); + close(fd); + continue; + } + + bytes = read(fd, &header, sizeof(struct amd_fw_header)); + if (bytes < (ssize_t)sizeof(struct amd_fw_header)) { + close(fd); + continue; + } + + /* If firmware header looks like invalid, assume it's not signed */ + if (!header.fw_type) { + close(fd); + continue; + } + + if (header.size_total != fd_stat.st_size) { + close(fd); + continue; + } + + if (header.sig_opt != 1) { + close(fd); + continue; + } + + buf = malloc(fd_stat.st_size); + + if (!buf) { + fprintf(stderr, "failed to allocate memory with size %lld\n", (long long)fd_stat.st_size); + close(fd); + continue; + } + + lseek(fd, SEEK_SET, 0); + bytes = read(fd, buf, fd_stat.st_size); + + if (bytes != fd_stat.st_size) { + fprintf(stderr, "failed to read : %lld %lld\n", + (long long)bytes, (long long)fd_stat.st_size); + free(buf); + close(fd); + continue; + } + + bytes = write(signed_rom_fd, buf, fd_stat.st_size); + + /* if failed to write, try again */ + if (bytes != fd_stat.st_size) { + ssize_t bytes2; + if (bytes < 0) + bytes = 0; + bytes2 = write(signed_rom_fd, buf + bytes, fd_stat.st_size - bytes); + + /* if failed again, give up and rewind file */ + if (bytes + bytes2 != fd_stat.st_size) { + if (bytes2 < 0) + bytes2 = 0; + lseek(signed_rom_fd, SEEK_CUR, -(bytes + bytes2)); + free(buf); + close(fd); + continue; + } + } + + fw_table[i].addr_signed = signed_start_addr; + fw_table[i].file_size = (uint32_t)fd_stat.st_size; + + signed_start_addr += fd_stat.st_size; + + free(buf); + close(fd); + } + + close(signed_rom_fd); +} + static void integrate_psp_firmwares(context *ctx, psp_directory_table *pspdir, psp_directory_table *pspdir2, @@ -709,21 +820,26 @@ BLOB_ERASE_ALIGNMENT); count++; } else if (fw_table[i].filename != NULL) { - bytes = copy_blob(BUFF_CURRENT(*ctx), - fw_table[i].filename, BUFF_ROOM(*ctx)); - if (bytes < 0) { - free(ctx->rom); - exit(1); + if (fw_table[i].addr_signed) { + pspdir->entries[count].addr = fw_table[i].addr_signed; + bytes = fw_table[i].file_size; + } else { + bytes = copy_blob(BUFF_CURRENT(*ctx), + fw_table[i].filename, BUFF_ROOM(*ctx)); + if (bytes < 0) { + free(ctx->rom); + exit(1); + } + pspdir->entries[count].addr = RUN_CURRENT(*ctx); + ctx->current = ALIGN(ctx->current + bytes, + BLOB_ALIGNMENT); }
pspdir->entries[count].type = fw_table[i].type; pspdir->entries[count].subprog = fw_table[i].subprog; pspdir->entries[count].rsvd = 0; pspdir->entries[count].size = (uint32_t)bytes; - pspdir->entries[count].addr = RUN_CURRENT(*ctx);
- ctx->current = ALIGN(ctx->current + bytes, - BLOB_ALIGNMENT); count++; } else { /* This APU doesn't have this firmware. */ @@ -1046,6 +1162,9 @@ AMDFW_OPT_SHAREDMEM, AMDFW_OPT_SHAREDMEM_SIZE, AMDFW_OPT_SOC_NAME, + + AMDFW_OPT_SIGNED_OUTPUT, + AMDFW_OPT_SIGNED_ADDR, /* begin after ASCII characters */ LONGOPT_SPI_READ_MODE = 256, LONGOPT_SPI_SPEED = 257, @@ -1096,6 +1215,9 @@ {"sharedmem-size", required_argument, 0, AMDFW_OPT_SHAREDMEM_SIZE }, {"soc-name", required_argument, 0, AMDFW_OPT_SOC_NAME },
+ {"signed-output", required_argument, 0, AMDFW_OPT_SIGNED_OUTPUT }, + {"signed-addr", required_argument, 0, AMDFW_OPT_SIGNED_ADDR }, + {"config", required_argument, 0, AMDFW_OPT_CONFIG }, {"debug", no_argument, 0, AMDFW_OPT_DEBUG }, {"help", no_argument, 0, AMDFW_OPT_HELP }, @@ -1291,6 +1413,9 @@ uint8_t efs_spi_speed = 0xff; uint8_t efs_spi_micron_flag = 0xff;
+ const char *signed_output_file = NULL; + uint64_t signed_start_addr = 0x0; + amd_cb_config cb_config; int debug = 0; int list_deps = 0; @@ -1423,6 +1548,14 @@ } sub = instance = 0; break; + case AMDFW_OPT_SIGNED_OUTPUT: + signed_output_file = optarg; + sub = instance = 0; + break; + case AMDFW_OPT_SIGNED_ADDR: + signed_start_addr = strtoull(optarg, NULL, 16); + sub = instance = 0; + break; case LONGOPT_SPI_READ_MODE: efs_spi_readmode = strtoull(optarg, NULL, 16); sub = instance = 0; @@ -1602,6 +1735,11 @@
ctx.current = ALIGN(ctx.current, 0x10000U); /* TODO: is it necessary? */
+ if (signed_output_file && signed_start_addr) + process_signed_psp_firmwares(signed_output_file, + amd_psp_fw_table, + signed_start_addr); + if (cb_config.multi_level) { /* Do 2nd PSP directory followed by 1st */ psp_directory_table *pspdir2 = new_psp_dir(&ctx, cb_config.multi_level); diff --git a/util/amdfwtool/amdfwtool.h b/util/amdfwtool/amdfwtool.h index a7ac7c1..07c4760 100644 --- a/util/amdfwtool/amdfwtool.h +++ b/util/amdfwtool/amdfwtool.h @@ -218,8 +218,32 @@ uint8_t subprog; int level; uint64_t other; + uint64_t addr_signed; + uint32_t file_size; } amd_fw_entry;
+struct amd_fw_header { + uint8_t reserved_0[20]; + uint32_t fw_size_signed; + uint8_t reserved_18[24]; + /* 1 if the image is signed, 0 otherwise */ + uint32_t sig_opt; + uint32_t sig_id; + uint8_t sig_param[16]; + uint32_t comp_opt; + uint8_t reserved_4c[4]; + uint32_t uncomp_size; + uint32_t comp_size; + uint8_t reserved_58[20]; + uint32_t size_total; + uint8_t reserved_70[12]; + uint8_t fw_type; + uint8_t fw_subtype; + uint8_t fw_subprog; + uint8_t reserved_7f; + uint8_t reserved_80[128]; +} __attribute__((packed)); + typedef struct _amd_cb_config { bool have_whitelist; bool unlock_secure;