diff options
-rw-r--r-- | util/amdfwtool/amdfwtool.c | 132 |
1 files changed, 119 insertions, 13 deletions
diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c index e28d9c4014..997a948bae 100644 --- a/util/amdfwtool/amdfwtool.c +++ b/util/amdfwtool/amdfwtool.c @@ -49,6 +49,7 @@ #include <commonlib/bsd/helpers.h> #include <fcntl.h> #include <errno.h> +#include <limits.h> #include <openssl/sha.h> #include <stdbool.h> #include <stdio.h> @@ -85,6 +86,8 @@ enum signature_id { SIG_ID_RSA4096 = 2, }; #define HASH_FILE_SUFFIX ".hash" +#define EFS_FILE_SUFFIX ".efs" +#define TMP_FILE_SUFFIX ".tmp" /* * Beginning with Family 15h Models 70h-7F, a.k.a Stoney Ridge, the PSP @@ -781,7 +784,6 @@ static void integrate_firmwares(context *ctx, ssize_t bytes; uint32_t i; - ctx->current += sizeof(embedded_firmware); ctx->current = ALIGN_UP(ctx->current, BLOB_ALIGNMENT); for (i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { @@ -1702,6 +1704,7 @@ enum { AMDFW_OPT_SOC_NAME, AMDFW_OPT_SIGNED_OUTPUT, AMDFW_OPT_SIGNED_ADDR, + AMDFW_OPT_BODY_LOCATION, /* begin after ASCII characters */ LONGOPT_SPI_READ_MODE = 256, LONGOPT_SPI_SPEED = 257, @@ -1753,6 +1756,7 @@ static struct option long_options[] = { {"spi-read-mode", required_argument, 0, LONGOPT_SPI_READ_MODE }, {"spi-speed", required_argument, 0, LONGOPT_SPI_SPEED }, {"spi-micron-flag", required_argument, 0, LONGOPT_SPI_MICRON_FLAG }, + {"body-location", required_argument, 0, AMDFW_OPT_BODY_LOCATION }, /* other */ {"output", required_argument, 0, AMDFW_OPT_OUTPUT }, {"flashsize", required_argument, 0, AMDFW_OPT_FLASHSIZE }, @@ -1945,6 +1949,54 @@ static int set_efs_table(uint8_t soc_id, amd_cb_config *cb_config, return 0; } +static ssize_t write_efs(char *output, embedded_firmware *amd_romsig) +{ + char efs_name[PATH_MAX], efs_tmp_name[PATH_MAX]; + int ret; + int fd; + ssize_t bytes = -1; + + /* Create a tmp file and rename it at the end so that make does not get confused + if amdfwtool is killed for some unexpected reasons. */ + ret = snprintf(efs_tmp_name, sizeof(efs_tmp_name), "%s%s%s", + output, EFS_FILE_SUFFIX, TMP_FILE_SUFFIX); + if (ret < 0) { + fprintf(stderr, "Error %s forming EFS tmp file name: %d\n", + strerror(errno), ret); + exit(1); + } else if ((unsigned int)ret >= sizeof(efs_tmp_name)) { + fprintf(stderr, "EFS File name %d > %zu\n", ret, sizeof(efs_tmp_name)); + exit(1); + } + + fd = open(efs_tmp_name, O_RDWR | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + fprintf(stderr, "Error: Opening %s file: %s\n", efs_tmp_name, strerror(errno)); + exit(1); + } + + bytes = write_from_buf_to_file(fd, amd_romsig, sizeof(*amd_romsig)); + if (bytes != sizeof(*amd_romsig)) { + fprintf(stderr, "Error: Writing to file %s failed\n", efs_tmp_name); + exit(1); + } + close(fd); + + /* Rename the tmp file */ + ret = snprintf(efs_name, sizeof(efs_name), "%s%s", output, EFS_FILE_SUFFIX); + if (ret < 0) { + fprintf(stderr, "Error %s forming EFS file name: %d\n", strerror(errno), ret); + exit(1); + } + + if (rename(efs_tmp_name, efs_name)) { + fprintf(stderr, "Error: renaming file %s to %s\n", efs_tmp_name, efs_name); + exit(1); + } + + return bytes; +} + static int identify_platform(char *soc_name) { if (!strcasecmp(soc_name, "Stoneyridge")) @@ -2016,6 +2068,7 @@ int main(int argc, char **argv) /* Values cleared after each firmware or parameter, regardless if N/A */ uint8_t sub = 0, instance = 0; uint32_t dir_location = 0; + uint32_t efs_location = 0; bool any_location = 0; uint32_t romsig_offset; uint32_t rom_base_address; @@ -2203,12 +2256,13 @@ int main(int argc, char **argv) } break; case AMDFW_OPT_LOCATION: - dir_location = (uint32_t)strtoul(optarg, &tmp, 16); + efs_location = (uint32_t)strtoul(optarg, &tmp, 16); if (*tmp != '\0') { fprintf(stderr, "Error: Directory Location specified" " incorrectly (%s)\n\n", optarg); retval = 1; } + dir_location = efs_location; break; case AMDFW_OPT_ANYWHERE: any_location = 1; @@ -2245,6 +2299,15 @@ int main(int argc, char **argv) case AMDFW_OPT_LIST_DEPEND: list_deps = 1; break; + case AMDFW_OPT_BODY_LOCATION: + dir_location = (uint32_t)strtoul(optarg, &tmp, 16); + if (*tmp != '\0') { + fprintf(stderr, "Error: Body Location specified" + " incorrectly (%s)\n\n", optarg); + retval = 1; + } + break; + default: break; } @@ -2313,19 +2376,42 @@ int main(int argc, char **argv) printf(" AMDFWTOOL Using ROM size of %dKB\n", ctx.rom_size / 1024); rom_base_address = 0xFFFFFFFF - ctx.rom_size + 1; - if (dir_location && (dir_location < rom_base_address)) { - fprintf(stderr, "Error: Directory location outside of ROM.\n\n"); + if (efs_location && (efs_location < rom_base_address)) { + fprintf(stderr, "Error: EFS/Directory location outside of ROM.\n\n"); + return 1; + } + + if (!efs_location && dir_location) { + fprintf(stderr, "Error AMDFW body location specified without EFS location.\n"); + return 1; + } + + /* + * On boards using vboot, there can be more than one instance of EFS + AMDFW Body. + * For the instance in the RO section, there is no need to split EFS + AMDFW body + * currently. This condition is to ensure that it is not accidentally split. Revisit + * this condition if such a need arises in the future. + */ + if (!any_location && dir_location != efs_location) { + fprintf(stderr, "Error: EFS cannot be separate from AMDFW Body.\n"); + return 1; + } + + if (dir_location != efs_location && + dir_location < ALIGN(efs_location + sizeof(embedded_firmware), BLOB_ALIGNMENT)) { + fprintf(stderr, "Error: Insufficient space between EFS and Blobs.\n"); + fprintf(stderr, " Require safe spacing of 256 bytes\n"); return 1; } if (any_location) { - if (dir_location & 0x3f) { - fprintf(stderr, "Error: Invalid Directory location.\n"); + if ((dir_location & 0x3f) || (efs_location & 0x3f)) { + fprintf(stderr, "Error: Invalid Directory/EFS location.\n"); fprintf(stderr, " Valid locations are 64-byte aligned\n"); return 1; } } else { - switch (dir_location) { + switch (efs_location) { case 0: /* Fall through */ case 0xFFFA0000: /* Fall through */ case 0xFFF20000: /* Fall through */ @@ -2348,10 +2434,18 @@ int main(int argc, char **argv) } memset(ctx.rom, 0xFF, ctx.rom_size); - if (dir_location) - romsig_offset = ctx.current = dir_location - rom_base_address; - else - romsig_offset = ctx.current = AMD_ROMSIG_OFFSET; + if (efs_location) { + if (efs_location != dir_location) { + romsig_offset = efs_location - rom_base_address; + ctx.current = dir_location - rom_base_address; + } else { + romsig_offset = efs_location - rom_base_address; + ctx.current = romsig_offset + sizeof(embedded_firmware); + } + } else { + romsig_offset = AMD_ROMSIG_OFFSET; + ctx.current = romsig_offset + sizeof(embedded_firmware); + } amd_romsig = BUFF_OFFSET(ctx, romsig_offset); amd_romsig->signature = EMBEDDED_FW_SIGNATURE; @@ -2497,8 +2591,10 @@ int main(int argc, char **argv) targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666); if (targetfd >= 0) { ssize_t bytes; - bytes = write(targetfd, amd_romsig, ctx.current - romsig_offset); - if (bytes != ctx.current - romsig_offset) { + uint32_t offset = dir_location ? dir_location - rom_base_address : AMD_ROMSIG_OFFSET; + + bytes = write(targetfd, BUFF_OFFSET(ctx, offset), ctx.current - offset); + if (bytes != ctx.current - offset) { fprintf(stderr, "Error: Writing to file %s failed\n", output); retval = 1; } @@ -2508,6 +2604,16 @@ int main(int argc, char **argv) retval = 1; } + if (efs_location != dir_location) { + ssize_t bytes; + + bytes = write_efs(output, amd_romsig); + if (bytes != sizeof(*amd_romsig)) { + fprintf(stderr, "Error: Writing EFS\n"); + retval = 1; + } + } + free(rom); return retval; } |