summaryrefslogtreecommitdiff
path: root/util/amdfwtool
diff options
context:
space:
mode:
authorZheng Bao <fishbaozi@gmail.com>2023-03-22 12:50:36 +0800
committerFelix Held <felix-coreboot@felixheld.de>2023-03-24 14:04:31 +0000
commitf080cd5463d5b12ad854b18be6114d8d79243218 (patch)
tree777f7f3288c25dadd533f65c0e6a3de567030380 /util/amdfwtool
parent94927888c7740a602f363c402da4b10282f0e616 (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>
Diffstat (limited to 'util/amdfwtool')
-rw-r--r--util/amdfwtool/Makefile2
-rw-r--r--util/amdfwtool/Makefile.inc2
-rw-r--r--util/amdfwtool/amdfwtool.c410
-rw-r--r--util/amdfwtool/amdfwtool.h14
-rw-r--r--util/amdfwtool/handle_file.c84
-rw-r--r--util/amdfwtool/signed_psp.c346
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);
+}