diff --git a/src/soc/amd/common/psp_verstage/include/psp_verstage.h b/src/soc/amd/common/psp_verstage/include/psp_verstage.h index 3b524c310c..e740332862 100644 --- a/src/soc/amd/common/psp_verstage/include/psp_verstage.h +++ b/src/soc/amd/common/psp_verstage/include/psp_verstage.h @@ -66,4 +66,6 @@ int platform_set_sha_op(enum vb2_hash_algorithm hash_alg, struct sha_generic_data *sha_op); void platform_report_mode(int developer_mode_enabled); +void update_psp_fw_hash_table(const char *fname); + #endif /* PSP_VERSTAGE_H */ diff --git a/src/soc/amd/common/psp_verstage/psp_verstage.c b/src/soc/amd/common/psp_verstage/psp_verstage.c index b928a27e27..0dc3314ca5 100644 --- a/src/soc/amd/common/psp_verstage/psp_verstage.c +++ b/src/soc/amd/common/psp_verstage/psp_verstage.c @@ -74,6 +74,7 @@ static uint32_t update_boot_region(struct vb2_context *ctx) uint32_t psp_dir_addr, bios_dir_addr; uint32_t *psp_dir_in_spi, *bios_dir_in_spi; const char *fname; + const char *hash_fname; void *amdfw_location; void *boot_dev_base = rdev_mmap_full(boot_device_ro()); @@ -85,8 +86,10 @@ static uint32_t update_boot_region(struct vb2_context *ctx) if (vboot_is_firmware_slot_a(ctx)) { fname = "apu/amdfw_a"; + hash_fname = "apu/amdfw_a_hash"; } else { fname = "apu/amdfw_b"; + hash_fname = "apu/amdfw_b_hash"; } amdfw_location = cbfs_map(fname, NULL); @@ -130,6 +133,9 @@ static uint32_t update_boot_region(struct vb2_context *ctx) return POSTCODE_UPDATE_PSP_BIOS_DIR_ERROR; } + if (CONFIG(SEPARATE_SIGNED_PSPFW)) + update_psp_fw_hash_table(hash_fname); + return 0; } diff --git a/src/soc/amd/mendocino/psp_verstage/chipset.c b/src/soc/amd/mendocino/psp_verstage/chipset.c index d4a33f0832..b89627981c 100644 --- a/src/soc/amd/mendocino/psp_verstage/chipset.c +++ b/src/soc/amd/mendocino/psp_verstage/chipset.c @@ -3,9 +3,67 @@ /* TODO: Check if this is still correct */ #include +#include #include #include +/* + * We can't pass pointer to hash table in the SPI. + * The AMD PSP team specifically required that whole hash table + * should be copied into memory before passing them to the PSP + * to reduce window of TOCTOU. + */ +#define MAX_NUM_HASH_ENTRIES 128 +static struct psp_fw_hash_table hash_table; +static struct psp_fw_entry_hash_256 hash_256[MAX_NUM_HASH_ENTRIES]; +static struct psp_fw_entry_hash_384 hash_384[MAX_NUM_HASH_ENTRIES]; + +void update_psp_fw_hash_table(const char *fname) +{ + uint8_t *spi_ptr = (uint8_t *)cbfs_map(fname, NULL); + uint32_t len; + + if (!spi_ptr) { + printk(BIOS_ERR, "Error: AMD Firmware hash table %s not found\n", fname); + /* + * If we don't supply hash table, the PSP will refuse to boot. + * So returning here is safe to do. + */ + return; + } + + memcpy(&hash_table, spi_ptr, offsetof(struct psp_fw_hash_table, fw_hash_256)); + + if (hash_table.no_of_entries_256 > MAX_NUM_HASH_ENTRIES || + hash_table.no_of_entries_384 > MAX_NUM_HASH_ENTRIES) { + printk(BIOS_ERR, "Error: Too many entries in AMD Firmware hash table" + " (SHA256:%d, SHA384:%d)\n", + hash_table.no_of_entries_256, hash_table.no_of_entries_384); + return; + } + + if (hash_table.no_of_entries_256 == 0 && + hash_table.no_of_entries_384 == 0) { + printk(BIOS_ERR, "Error: No entries in AMD Firmware hash table" + " (SHA256:%d, SHA384:%d)\n", + hash_table.no_of_entries_256, hash_table.no_of_entries_384); + return; + } + + spi_ptr += offsetof(struct psp_fw_hash_table, fw_hash_256); + + hash_table.fw_hash_256 = hash_256; + hash_table.fw_hash_384 = hash_384; + len = sizeof(struct psp_fw_entry_hash_256) * hash_table.no_of_entries_256; + memcpy(hash_256, spi_ptr, len); + + spi_ptr += len; + len = sizeof(struct psp_fw_entry_hash_384) * hash_table.no_of_entries_384; + memcpy(hash_384, spi_ptr, len); + + svc_set_fw_hash_table(&hash_table); +} + uint32_t update_psp_bios_dir(uint32_t *psp_dir_offset, uint32_t *bios_dir_offset) { return svc_update_psp_bios_dir(psp_dir_offset, bios_dir_offset);