diff options
author | Zheng Bao <fishbaozi@gmail.com> | 2023-03-22 12:50:36 +0800 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2023-03-24 14:04:31 +0000 |
commit | f080cd5463d5b12ad854b18be6114d8d79243218 (patch) | |
tree | 777f7f3288c25dadd533f65c0e6a3de567030380 | |
parent | 94927888c7740a602f363c402da4b10282f0e616 (diff) |
amdfwtool: Move some funtions to other categorized source files
To reduce the size of amdfwtool.c which is already too big.
Change-Id: Ib80eeb42f59a3dda04402b2feaadc1d178ed989e
Signed-off-by: Zheng Bao <fishbaozi@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/73910
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Fred Reitberger <reitbergerfred@gmail.com>
-rw-r--r-- | util/amdfwtool/Makefile | 2 | ||||
-rw-r--r-- | util/amdfwtool/Makefile.inc | 2 | ||||
-rw-r--r-- | util/amdfwtool/amdfwtool.c | 410 | ||||
-rw-r--r-- | util/amdfwtool/amdfwtool.h | 14 | ||||
-rw-r--r-- | util/amdfwtool/handle_file.c | 84 | ||||
-rw-r--r-- | util/amdfwtool/signed_psp.c | 346 |
6 files changed, 445 insertions, 413 deletions
diff --git a/util/amdfwtool/Makefile b/util/amdfwtool/Makefile index 53dce4c8c7..8ec4e9bb6f 100644 --- a/util/amdfwtool/Makefile +++ b/util/amdfwtool/Makefile @@ -9,7 +9,7 @@ endif READ_SRC = amdfwread.c READ_OBJ = $(READ_SRC:%.c=%.o) -TOOL_SRC = amdfwtool.c data_parse.c +TOOL_SRC = amdfwtool.c data_parse.c signed_psp.c handle_file.c TOOL_OBJ = $(TOOL_SRC:%.c=%.o) HEADER=amdfwtool.h TARGETS = amdfwread amdfwtool diff --git a/util/amdfwtool/Makefile.inc b/util/amdfwtool/Makefile.inc index b9c3ced74d..7d96155736 100644 --- a/util/amdfwtool/Makefile.inc +++ b/util/amdfwtool/Makefile.inc @@ -1,6 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause -amdfwtoolobj = amdfwtool.o data_parse.o +amdfwtoolobj = amdfwtool.o data_parse.o signed_psp.o handle_file.o amdfwreadobj = amdfwread.o AMDFWTOOLCFLAGS=-O2 -Wall -Wextra -Wshadow -Werror diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c index 9312be670c..8190b8dc2a 100644 --- a/util/amdfwtool/amdfwtool.c +++ b/util/amdfwtool/amdfwtool.c @@ -73,7 +73,6 @@ #include <fcntl.h> #include <errno.h> #include <limits.h> -#include <openssl/sha.h> #include <stdbool.h> #include <stdio.h> #include <sys/stat.h> @@ -91,24 +90,9 @@ #define MIN_ROM_KB 256 #define _MAX(A, B) (((A) > (B)) ? (A) : (B)) -#define ERASE_ALIGNMENT 0x1000U -#define TABLE_ALIGNMENT 0x1000U -#define BLOB_ALIGNMENT 0x100U -#define TABLE_ERASE_ALIGNMENT _MAX(TABLE_ALIGNMENT, ERASE_ALIGNMENT) -#define BLOB_ERASE_ALIGNMENT _MAX(BLOB_ALIGNMENT, ERASE_ALIGNMENT) #define DEFAULT_SOFT_FUSE_CHAIN "0x1" -/* Defines related to hashing signed binaries */ -enum hash_header_ver { - HASH_HDR_V1 = 1, -}; -/* Signature ID enums are defined by PSP based on the algorithm used. */ -enum signature_id { - SIG_ID_RSA2048, - SIG_ID_RSA4096 = 2, -}; -#define HASH_FILE_SUFFIX ".hash" #define EFS_FILE_SUFFIX ".efs" #define TMP_FILE_SUFFIX ".tmp" #define BODY_FILE_SUFFIX ".body" @@ -776,66 +760,6 @@ static ssize_t copy_blob(void *dest, const char *src_file, size_t room) return bytes; } -static ssize_t read_from_file_to_buf(int fd, void *buf, size_t buf_size) -{ - ssize_t bytes; - size_t total_bytes = 0; - - do { - bytes = read(fd, buf + total_bytes, buf_size - total_bytes); - if (bytes == 0) { - fprintf(stderr, "Reached EOF probably\n"); - break; - } - - if (bytes < 0 && errno == EAGAIN) - bytes = 0; - - if (bytes < 0) { - fprintf(stderr, "Read failure %s\n", strerror(errno)); - return bytes; - } - - total_bytes += bytes; - } while (total_bytes < buf_size); - - if (total_bytes != buf_size) { - fprintf(stderr, "Read data size(%zu) != buffer size(%zu)\n", - total_bytes, buf_size); - return -1; - } - return buf_size; -} - -static ssize_t write_from_buf_to_file(int fd, const void *buf, size_t buf_size) -{ - ssize_t bytes; - size_t total_bytes = 0; - - do { - bytes = write(fd, buf + total_bytes, buf_size - total_bytes); - if (bytes < 0 && errno == EAGAIN) - bytes = 0; - - if (bytes < 0) { - fprintf(stderr, "Write failure %s\n", strerror(errno)); - lseek(fd, SEEK_CUR, -total_bytes); - return bytes; - } - - total_bytes += bytes; - } while (total_bytes < buf_size); - - if (total_bytes != buf_size) { - fprintf(stderr, "Wrote more data(%zu) than buffer size(%zu)\n", - total_bytes, buf_size); - lseek(fd, SEEK_CUR, -total_bytes); - return -1; - } - - return buf_size; -} - static uint32_t get_psp_id(enum platform soc_id) { uint32_t psp_id; @@ -871,99 +795,6 @@ static uint32_t get_psp_id(enum platform soc_id) return psp_id; } -static uint16_t get_psp_fw_type(enum platform soc_id, struct amd_fw_header *header) -{ - switch (soc_id) { - case PLATFORM_MENDOCINO: - case PLATFORM_PHOENIX: - case PLATFORM_GLINDA: - /* Fallback to fw_type if fw_id is not populated, which serves the same - purpose on older SoCs. */ - return header->fw_id ? header->fw_id : header->fw_type; - default: - return header->fw_type; - } -} - -static int add_single_sha(amd_fw_entry_hash *entry, void *buf, enum platform soc_id) -{ - uint8_t hash[SHA384_DIGEST_LENGTH]; - struct amd_fw_header *header = (struct amd_fw_header *)buf; - /* Include only signed part for hash calculation. */ - size_t len = header->fw_size_signed + sizeof(struct amd_fw_header); - uint8_t *body = (uint8_t *)buf; - - if (len > header->size_total) - return -1; - - if (header->sig_id == SIG_ID_RSA4096) { - SHA384(body, len, hash); - entry->sha_len = SHA384_DIGEST_LENGTH; - } else if (header->sig_id == SIG_ID_RSA2048) { - SHA256(body, len, hash); - entry->sha_len = SHA256_DIGEST_LENGTH; - } else { - fprintf(stderr, "%s: Unknown signature id: 0x%08x\n", - __func__, header->sig_id); - return -1; - } - - memcpy(entry->sha, hash, entry->sha_len); - entry->fw_id = get_psp_fw_type(soc_id, header); - entry->subtype = header->fw_subtype; - - return 0; -} - -static int get_num_binaries(void *buf, size_t buf_size) -{ - struct amd_fw_header *header = (struct amd_fw_header *)buf; - size_t total_len = 0; - int num_binaries = 0; - - while (total_len < buf_size) { - num_binaries++; - total_len += header->size_total; - header = (struct amd_fw_header *)(buf + total_len); - } - - if (total_len != buf_size) { - fprintf(stderr, "Malformed binary\n"); - return -1; - } - return num_binaries; -} - -static int add_sha(amd_fw_entry *entry, void *buf, size_t buf_size, enum platform soc_id) -{ - struct amd_fw_header *header = (struct amd_fw_header *)buf; - /* Include only signed part for hash calculation. */ - size_t total_len = 0; - int num_binaries = get_num_binaries(buf, buf_size); - - if (num_binaries <= 0) - return num_binaries; - - entry->hash_entries = malloc(num_binaries * sizeof(amd_fw_entry_hash)); - if (!entry->hash_entries) { - fprintf(stderr, "Error allocating memory to add FW hash\n"); - return -1; - } - entry->num_hash_entries = num_binaries; - - /* Iterate through each binary */ - for (int i = 0; i < num_binaries; i++) { - if (add_single_sha(&entry->hash_entries[i], buf + total_len, soc_id)) { - free(entry->hash_entries); - return -1; - } - total_len += header->size_total; - header = (struct amd_fw_header *)(buf + total_len); - } - - return 0; -} - static void integrate_firmwares(context *ctx, embedded_firmware *romsig, amd_fw_entry *fw_table) @@ -1026,247 +857,6 @@ static void dump_bdt_firmwares(amd_bios_entry *fw_table) } } -static void write_or_fail(int fd, void *ptr, size_t size) -{ - ssize_t written; - - written = write_from_buf_to_file(fd, ptr, size); - if (written < 0 || (size_t)written != size) { - fprintf(stderr, "%s: Error writing %zu bytes - written %zd bytes\n", - __func__, size, written); - exit(-1); - } -} - -static void write_one_psp_firmware_hash_entry(int fd, amd_fw_entry_hash *entry) -{ - uint16_t type = entry->fw_id; - uint16_t subtype = entry->subtype; - - write_or_fail(fd, &type, sizeof(type)); - write_or_fail(fd, &subtype, sizeof(subtype)); - write_or_fail(fd, entry->sha, entry->sha_len); -} - -static void write_psp_firmware_hash(const char *filename, - amd_fw_entry *fw_table) -{ - struct psp_fw_hash_table hash_header = {0}; - int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666); - - if (fd < 0) { - fprintf(stderr, "Error opening file: %s: %s\n", - filename, strerror(errno)); - exit(-1); - } - - hash_header.version = HASH_HDR_V1; - for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { - for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { - if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) { - hash_header.no_of_entries_256++; - } else if (fw_table[i].hash_entries[j].sha_len == - SHA384_DIGEST_LENGTH) { - hash_header.no_of_entries_384++; - } else if (fw_table[i].hash_entries[j].sha_len) { - fprintf(stderr, "%s: Error invalid sha_len %d\n", - __func__, fw_table[i].hash_entries[j].sha_len); - exit(-1); - } - } - } - - write_or_fail(fd, &hash_header, sizeof(hash_header)); - - /* Add all the SHA256 hash entries first followed by SHA384 entries. PSP verstage - processes the table in that order. Mixing and matching SHA256 and SHA384 entries - will cause the hash verification failure at run-time. */ - for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { - for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { - if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) - write_one_psp_firmware_hash_entry(fd, - &fw_table[i].hash_entries[j]); - } - } - - for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { - for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { - if (fw_table[i].hash_entries[j].sha_len == SHA384_DIGEST_LENGTH) - write_one_psp_firmware_hash_entry(fd, - &fw_table[i].hash_entries[j]); - } - } - - close(fd); - for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { - if (!fw_table[i].num_hash_entries || !fw_table[i].hash_entries) - continue; - - free(fw_table[i].hash_entries); - fw_table[i].hash_entries = NULL; - fw_table[i].num_hash_entries = 0; - } -} - -/** - * process_signed_psp_firmwares() - Process the signed PSP binaries to keep them separate - * @signed_rom: Output file path grouping all the signed PSP binaries. - * @fw_table: Table of all the PSP firmware entries/binaries to be processed. - * @signed_start_addr: Offset of the FMAP section, within the flash device, to hold - * the signed PSP binaries. - * @soc_id: SoC ID of the PSP binaries. - */ -static void process_signed_psp_firmwares(const char *signed_rom, - amd_fw_entry *fw_table, - uint64_t signed_start_addr, - enum platform soc_id) -{ - unsigned int i; - int fd; - int signed_rom_fd; - ssize_t bytes, align_bytes; - uint8_t *buf; - char *signed_rom_hash; - size_t signed_rom_hash_strlen; - struct amd_fw_header header; - struct stat fd_stat; - /* Every blob in amdfw*.rom has to start at address aligned to 0x100. Prepare an - alignment data with 0xff to pad the blobs and meet the alignment requirement. */ - uint8_t align_data[BLOB_ALIGNMENT - 1]; - - memset(align_data, 0xff, sizeof(align_data)); - signed_rom_fd = open(signed_rom, O_RDWR | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - 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++) { - fw_table[i].num_hash_entries = 0; - fw_table[i].hash_entries = NULL; - - if (!(fw_table[i].filename) || fw_table[i].skip_hashing) - continue; - - memset(&header, 0, sizeof(header)); - - fd = open(fw_table[i].filename, O_RDONLY); - if (fd < 0) { - /* Keep the file along with set of unsigned PSP binaries & continue. */ - fprintf(stderr, "Error opening file: %s: %s\n", - fw_table[i].filename, strerror(errno)); - continue; - } - - if (fstat(fd, &fd_stat)) { - /* Keep the file along with set of unsigned PSP binaries & continue. */ - fprintf(stderr, "fstat error: %s\n", strerror(errno)); - close(fd); - continue; - } - - bytes = read_from_file_to_buf(fd, &header, sizeof(struct amd_fw_header)); - if (bytes != (ssize_t)sizeof(struct amd_fw_header)) { - /* Keep the file along with set of unsigned PSP binaries & continue. */ - fprintf(stderr, "%s: Error reading header from %s\n", - __func__, fw_table[i].filename); - close(fd); - continue; - } - - /* If firmware header looks like invalid, assume it's not signed */ - if (!header.fw_type && !header.fw_id) { - fprintf(stderr, "%s: Invalid FWID for %s\n", - __func__, fw_table[i].filename); - close(fd); - continue; - } - - - /* PSP binary is not signed and should not be part of signed PSP binaries - set. */ - if (header.sig_opt != 1) { - close(fd); - continue; - } - - buf = malloc(fd_stat.st_size); - if (!buf) { - /* Keep the file along with set of unsigned PSP binaries & continue. */ - fprintf(stderr, "%s: failed to allocate memory with size %lld\n", - __func__, (long long)fd_stat.st_size); - close(fd); - continue; - } - - lseek(fd, SEEK_SET, 0); - bytes = read_from_file_to_buf(fd, buf, fd_stat.st_size); - if (bytes != fd_stat.st_size) { - /* Keep the file along with set of unsigned PSP binaries & continue. */ - fprintf(stderr, "%s: failed to read %s\n", - __func__, fw_table[i].filename); - free(buf); - close(fd); - continue; - } - - bytes = write_from_buf_to_file(signed_rom_fd, buf, fd_stat.st_size); - if (bytes != fd_stat.st_size) { - /* Keep the file along with set of unsigned PSP binaries & continue. */ - fprintf(stderr, "%s: failed to write %s\n", - __func__, fw_table[i].filename); - free(buf); - close(fd); - continue; - } - - /* Write Blob alignment bytes */ - align_bytes = 0; - if (fd_stat.st_size & (BLOB_ALIGNMENT - 1)) { - align_bytes = BLOB_ALIGNMENT - - (fd_stat.st_size & (BLOB_ALIGNMENT - 1)); - bytes = write_from_buf_to_file(signed_rom_fd, align_data, align_bytes); - if (bytes != align_bytes) { - fprintf(stderr, "%s: failed to write alignment data for %s\n", - __func__, fw_table[i].filename); - lseek(signed_rom_fd, SEEK_CUR, -fd_stat.st_size); - free(buf); - close(fd); - continue; - } - } - - if (add_sha(&fw_table[i], buf, fd_stat.st_size, soc_id)) - exit(-1); - - /* File is successfully processed and is part of signed PSP binaries set. */ - fw_table[i].fw_id = get_psp_fw_type(soc_id, &header); - 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 + align_bytes; - - free(buf); - close(fd); - } - - close(signed_rom_fd); - - /* signed_rom file name + ".hash" + '\0' */ - signed_rom_hash_strlen = strlen(signed_rom) + strlen(HASH_FILE_SUFFIX) + 1; - signed_rom_hash = malloc(signed_rom_hash_strlen); - if (!signed_rom_hash) { - fprintf(stderr, "malloc(%lu) failed\n", signed_rom_hash_strlen); - exit(-1); - } - strcpy(signed_rom_hash, signed_rom); - strcat(signed_rom_hash, HASH_FILE_SUFFIX); - write_psp_firmware_hash(signed_rom_hash, fw_table); - free(signed_rom_hash); -} - static void integrate_psp_ab(context *ctx, psp_directory_table *pspdir, psp_directory_table *pspdir2, ish_directory_table *ish, amd_fw_type ab, enum platform soc_id) diff --git a/util/amdfwtool/amdfwtool.h b/util/amdfwtool/amdfwtool.h index 5d6047c0c5..03cc056a26 100644 --- a/util/amdfwtool/amdfwtool.h +++ b/util/amdfwtool/amdfwtool.h @@ -9,6 +9,12 @@ #include <stdint.h> #include <stdbool.h> +#define ERASE_ALIGNMENT 0x1000U +#define TABLE_ALIGNMENT 0x1000U +#define BLOB_ALIGNMENT 0x100U +#define TABLE_ERASE_ALIGNMENT _MAX(TABLE_ALIGNMENT, ERASE_ALIGNMENT) +#define BLOB_ERASE_ALIGNMENT _MAX(BLOB_ALIGNMENT, ERASE_ALIGNMENT) + enum platform { PLATFORM_UNKNOWN, PLATFORM_CARRIZO, @@ -408,7 +414,13 @@ typedef struct _amd_cb_config { void register_fw_fuse(char *str); uint8_t process_config(FILE *config, amd_cb_config *cb_config); - +void process_signed_psp_firmwares(const char *signed_rom, + amd_fw_entry *fw_table, + uint64_t signed_start_addr, + enum platform soc_id); +void write_or_fail(int fd, void *ptr, size_t size); +ssize_t read_from_file_to_buf(int fd, void *buf, size_t buf_size); +ssize_t write_from_buf_to_file(int fd, const void *buf, size_t buf_size); #define OK 0 #define LINE_EOF (1) diff --git a/util/amdfwtool/handle_file.c b/util/amdfwtool/handle_file.c new file mode 100644 index 0000000000..884f1ba709 --- /dev/null +++ b/util/amdfwtool/handle_file.c @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <fcntl.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include "amdfwtool.h" + +void write_or_fail(int fd, void *ptr, size_t size) +{ + ssize_t written; + + written = write_from_buf_to_file(fd, ptr, size); + if (written < 0 || (size_t)written != size) { + fprintf(stderr, "%s: Error writing %zu bytes - written %zd bytes\n", + __func__, size, written); + exit(-1); + } +} + +ssize_t read_from_file_to_buf(int fd, void *buf, size_t buf_size) +{ + ssize_t bytes; + size_t total_bytes = 0; + + do { + bytes = read(fd, buf + total_bytes, buf_size - total_bytes); + if (bytes == 0) { + fprintf(stderr, "Reached EOF probably\n"); + break; + } + + if (bytes < 0 && errno == EAGAIN) + bytes = 0; + + if (bytes < 0) { + fprintf(stderr, "Read failure %s\n", strerror(errno)); + return bytes; + } + + total_bytes += bytes; + } while (total_bytes < buf_size); + + if (total_bytes != buf_size) { + fprintf(stderr, "Read data size(%zu) != buffer size(%zu)\n", + total_bytes, buf_size); + return -1; + } + return buf_size; +} + +ssize_t write_from_buf_to_file(int fd, const void *buf, size_t buf_size) +{ + ssize_t bytes; + size_t total_bytes = 0; + + do { + bytes = write(fd, buf + total_bytes, buf_size - total_bytes); + if (bytes < 0 && errno == EAGAIN) + bytes = 0; + + if (bytes < 0) { + fprintf(stderr, "Write failure %s\n", strerror(errno)); + lseek(fd, SEEK_CUR, -total_bytes); + return bytes; + } + + total_bytes += bytes; + } while (total_bytes < buf_size); + + if (total_bytes != buf_size) { + fprintf(stderr, "Wrote more data(%zu) than buffer size(%zu)\n", + total_bytes, buf_size); + lseek(fd, SEEK_CUR, -total_bytes); + return -1; + } + + return buf_size; +} diff --git a/util/amdfwtool/signed_psp.c b/util/amdfwtool/signed_psp.c new file mode 100644 index 0000000000..644e904f50 --- /dev/null +++ b/util/amdfwtool/signed_psp.c @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <fcntl.h> +#include <errno.h> +#include <limits.h> +#include <openssl/sha.h> +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include "amdfwtool.h" + +/* Defines related to hashing signed binaries */ +enum hash_header_ver { + HASH_HDR_V1 = 1, +}; +/* Signature ID enums are defined by PSP based on the algorithm used. */ +enum signature_id { + SIG_ID_RSA2048, + SIG_ID_RSA4096 = 2, +}; +#define HASH_FILE_SUFFIX ".hash" + +static uint16_t get_psp_fw_type(enum platform soc_id, struct amd_fw_header *header) +{ + switch (soc_id) { + case PLATFORM_MENDOCINO: + case PLATFORM_PHOENIX: + case PLATFORM_GLINDA: + /* Fallback to fw_type if fw_id is not populated, which serves the same + purpose on older SoCs. */ + return header->fw_id ? header->fw_id : header->fw_type; + default: + return header->fw_type; + } +} + +static int add_single_sha(amd_fw_entry_hash *entry, void *buf, enum platform soc_id) +{ + uint8_t hash[SHA384_DIGEST_LENGTH]; + struct amd_fw_header *header = (struct amd_fw_header *)buf; + /* Include only signed part for hash calculation. */ + size_t len = header->fw_size_signed + sizeof(struct amd_fw_header); + uint8_t *body = (uint8_t *)buf; + + if (len > header->size_total) + return -1; + + if (header->sig_id == SIG_ID_RSA4096) { + SHA384(body, len, hash); + entry->sha_len = SHA384_DIGEST_LENGTH; + } else if (header->sig_id == SIG_ID_RSA2048) { + SHA256(body, len, hash); + entry->sha_len = SHA256_DIGEST_LENGTH; + } else { + fprintf(stderr, "%s: Unknown signature id: 0x%08x\n", + __func__, header->sig_id); + return -1; + } + + memcpy(entry->sha, hash, entry->sha_len); + entry->fw_id = get_psp_fw_type(soc_id, header); + entry->subtype = header->fw_subtype; + + return 0; +} + +static int get_num_binaries(void *buf, size_t buf_size) +{ + struct amd_fw_header *header = (struct amd_fw_header *)buf; + size_t total_len = 0; + int num_binaries = 0; + + while (total_len < buf_size) { + num_binaries++; + total_len += header->size_total; + header = (struct amd_fw_header *)(buf + total_len); + } + + if (total_len != buf_size) { + fprintf(stderr, "Malformed binary\n"); + return -1; + } + return num_binaries; +} + +static int add_sha(amd_fw_entry *entry, void *buf, size_t buf_size, enum platform soc_id) +{ + struct amd_fw_header *header = (struct amd_fw_header *)buf; + /* Include only signed part for hash calculation. */ + size_t total_len = 0; + int num_binaries = get_num_binaries(buf, buf_size); + + if (num_binaries <= 0) + return num_binaries; + + entry->hash_entries = malloc(num_binaries * sizeof(amd_fw_entry_hash)); + if (!entry->hash_entries) { + fprintf(stderr, "Error allocating memory to add FW hash\n"); + return -1; + } + entry->num_hash_entries = num_binaries; + + /* Iterate through each binary */ + for (int i = 0; i < num_binaries; i++) { + if (add_single_sha(&entry->hash_entries[i], buf + total_len, soc_id)) { + free(entry->hash_entries); + return -1; + } + total_len += header->size_total; + header = (struct amd_fw_header *)(buf + total_len); + } + + return 0; +} + +static void write_one_psp_firmware_hash_entry(int fd, amd_fw_entry_hash *entry) +{ + uint16_t type = entry->fw_id; + uint16_t subtype = entry->subtype; + + write_or_fail(fd, &type, sizeof(type)); + write_or_fail(fd, &subtype, sizeof(subtype)); + write_or_fail(fd, entry->sha, entry->sha_len); +} + +static void write_psp_firmware_hash(const char *filename, + amd_fw_entry *fw_table) +{ + struct psp_fw_hash_table hash_header = {0}; + int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666); + + if (fd < 0) { + fprintf(stderr, "Error opening file: %s: %s\n", + filename, strerror(errno)); + exit(-1); + } + + hash_header.version = HASH_HDR_V1; + for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { + for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { + if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) { + hash_header.no_of_entries_256++; + } else if (fw_table[i].hash_entries[j].sha_len == + SHA384_DIGEST_LENGTH) { + hash_header.no_of_entries_384++; + } else if (fw_table[i].hash_entries[j].sha_len) { + fprintf(stderr, "%s: Error invalid sha_len %d\n", + __func__, fw_table[i].hash_entries[j].sha_len); + exit(-1); + } + } + } + + write_or_fail(fd, &hash_header, sizeof(hash_header)); + + /* Add all the SHA256 hash entries first followed by SHA384 entries. PSP verstage + processes the table in that order. Mixing and matching SHA256 and SHA384 entries + will cause the hash verification failure at run-time. */ + for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { + for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { + if (fw_table[i].hash_entries[j].sha_len == SHA256_DIGEST_LENGTH) + write_one_psp_firmware_hash_entry(fd, + &fw_table[i].hash_entries[j]); + } + } + + for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { + for (unsigned int j = 0; j < fw_table[i].num_hash_entries; j++) { + if (fw_table[i].hash_entries[j].sha_len == SHA384_DIGEST_LENGTH) + write_one_psp_firmware_hash_entry(fd, + &fw_table[i].hash_entries[j]); + } + } + + close(fd); + for (unsigned int i = 0; fw_table[i].type != AMD_FW_INVALID; i++) { + if (!fw_table[i].num_hash_entries || !fw_table[i].hash_entries) + continue; + + free(fw_table[i].hash_entries); + fw_table[i].hash_entries = NULL; + fw_table[i].num_hash_entries = 0; + } +} + +/** + * process_signed_psp_firmwares() - Process the signed PSP binaries to keep them separate + * @signed_rom: Output file path grouping all the signed PSP binaries. + * @fw_table: Table of all the PSP firmware entries/binaries to be processed. + * @signed_start_addr: Offset of the FMAP section, within the flash device, to hold + * the signed PSP binaries. + * @soc_id: SoC ID of the PSP binaries. + */ +void process_signed_psp_firmwares(const char *signed_rom, + amd_fw_entry *fw_table, + uint64_t signed_start_addr, + enum platform soc_id) +{ + unsigned int i; + int fd; + int signed_rom_fd; + ssize_t bytes, align_bytes; + uint8_t *buf; + char *signed_rom_hash; + size_t signed_rom_hash_strlen; + struct amd_fw_header header; + struct stat fd_stat; + /* Every blob in amdfw*.rom has to start at address aligned to 0x100. Prepare an + alignment data with 0xff to pad the blobs and meet the alignment requirement. */ + uint8_t align_data[BLOB_ALIGNMENT - 1]; + + memset(align_data, 0xff, sizeof(align_data)); + signed_rom_fd = open(signed_rom, O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + 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++) { + fw_table[i].num_hash_entries = 0; + fw_table[i].hash_entries = NULL; + + if (!(fw_table[i].filename) || fw_table[i].skip_hashing) + continue; + + memset(&header, 0, sizeof(header)); + + fd = open(fw_table[i].filename, O_RDONLY); + if (fd < 0) { + /* Keep the file along with set of unsigned PSP binaries & continue. */ + fprintf(stderr, "Error opening file: %s: %s\n", + fw_table[i].filename, strerror(errno)); + continue; + } + + if (fstat(fd, &fd_stat)) { + /* Keep the file along with set of unsigned PSP binaries & continue. */ + fprintf(stderr, "fstat error: %s\n", strerror(errno)); + close(fd); + continue; + } + + bytes = read_from_file_to_buf(fd, &header, sizeof(struct amd_fw_header)); + if (bytes != (ssize_t)sizeof(struct amd_fw_header)) { + /* Keep the file along with set of unsigned PSP binaries & continue. */ + fprintf(stderr, "%s: Error reading header from %s\n", + __func__, fw_table[i].filename); + close(fd); + continue; + } + + /* If firmware header looks like invalid, assume it's not signed */ + if (!header.fw_type && !header.fw_id) { + fprintf(stderr, "%s: Invalid FWID for %s\n", + __func__, fw_table[i].filename); + close(fd); + continue; + } + + + /* PSP binary is not signed and should not be part of signed PSP binaries + set. */ + if (header.sig_opt != 1) { + close(fd); + continue; + } + + buf = malloc(fd_stat.st_size); + if (!buf) { + /* Keep the file along with set of unsigned PSP binaries & continue. */ + fprintf(stderr, "%s: failed to allocate memory with size %lld\n", + __func__, (long long)fd_stat.st_size); + close(fd); + continue; + } + + lseek(fd, SEEK_SET, 0); + bytes = read_from_file_to_buf(fd, buf, fd_stat.st_size); + if (bytes != fd_stat.st_size) { + /* Keep the file along with set of unsigned PSP binaries & continue. */ + fprintf(stderr, "%s: failed to read %s\n", + __func__, fw_table[i].filename); + free(buf); + close(fd); + continue; + } + + bytes = write_from_buf_to_file(signed_rom_fd, buf, fd_stat.st_size); + if (bytes != fd_stat.st_size) { + /* Keep the file along with set of unsigned PSP binaries & continue. */ + fprintf(stderr, "%s: failed to write %s\n", + __func__, fw_table[i].filename); + free(buf); + close(fd); + continue; + } + + /* Write Blob alignment bytes */ + align_bytes = 0; + if (fd_stat.st_size & (BLOB_ALIGNMENT - 1)) { + align_bytes = BLOB_ALIGNMENT - + (fd_stat.st_size & (BLOB_ALIGNMENT - 1)); + bytes = write_from_buf_to_file(signed_rom_fd, align_data, align_bytes); + if (bytes != align_bytes) { + fprintf(stderr, "%s: failed to write alignment data for %s\n", + __func__, fw_table[i].filename); + lseek(signed_rom_fd, SEEK_CUR, -fd_stat.st_size); + free(buf); + close(fd); + continue; + } + } + + if (add_sha(&fw_table[i], buf, fd_stat.st_size, soc_id)) + exit(-1); + + /* File is successfully processed and is part of signed PSP binaries set. */ + fw_table[i].fw_id = get_psp_fw_type(soc_id, &header); + 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 + align_bytes; + + free(buf); + close(fd); + } + + close(signed_rom_fd); + + /* signed_rom file name + ".hash" + '\0' */ + signed_rom_hash_strlen = strlen(signed_rom) + strlen(HASH_FILE_SUFFIX) + 1; + signed_rom_hash = malloc(signed_rom_hash_strlen); + if (!signed_rom_hash) { + fprintf(stderr, "malloc(%lu) failed\n", signed_rom_hash_strlen); + exit(-1); + } + strcpy(signed_rom_hash, signed_rom); + strcat(signed_rom_hash, HASH_FILE_SUFFIX); + write_psp_firmware_hash(signed_rom_hash, fw_table); + free(signed_rom_hash); +} |