diff options
Diffstat (limited to 'src/soc')
-rw-r--r-- | src/soc/amd/common/block/psp/Kconfig | 9 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp_def.h | 7 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/rpmc.c | 99 |
3 files changed, 115 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/psp/Kconfig b/src/soc/amd/common/block/psp/Kconfig index 9262e47d7d..3ae5e439f6 100644 --- a/src/soc/amd/common/block/psp/Kconfig +++ b/src/soc/amd/common/block/psp/Kconfig @@ -38,6 +38,15 @@ config SOC_AMD_COMMON_BLOCK_PSP_RPMC Select this option in the SoC's Kconfig to include the support for the replay-protected monotonic counter (RPMC) feature. +config PERFORM_RPMC_PROVISIONING + bool "Send RPMC fusing command to PSP" + default n + depends on SOC_AMD_COMMON_BLOCK_PSP_RPMC + help + Send the RPMC root key provisioning command to the PSP in case it's + not already fused. Sending this command will fuse the silicon which + is a permanent change. + config SOC_AMD_COMMON_BLOCK_PSP_SPL bool help diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h index d1f57ac19c..d11199db39 100644 --- a/src/soc/amd/common/block/psp/psp_def.h +++ b/src/soc/amd/common/block/psp/psp_def.h @@ -27,6 +27,7 @@ #define MBOX_BIOS_CMD_PSB_AUTO_FUSING 0x21 #define MBOX_BIOS_CMD_PSP_CAPS_QUERY 0x27 #define MBOX_BIOS_CMD_SET_SPL_FUSE 0x2d +#define MBOX_BIOS_CMD_SET_RPMC_ADDRESS 0x39 #define MBOX_BIOS_CMD_QUERY_SPL_FUSE 0x47 #define MBOX_BIOS_CMD_I2C_TPM_ARBITRATION 0x64 #define MBOX_BIOS_CMD_ABORT 0xfe @@ -98,6 +99,12 @@ struct mbox_cmd_hsti_query_buffer { uint32_t state; } __packed __aligned(32); +/* MBOX_BIOS_CMD_SET_RPMC_ADDRESS */ +struct mbox_cmd_set_rpmc_address_buffer { + struct mbox_buffer_header header; + uint32_t address; +} __packed __aligned(32); + /* MBOX_BIOS_CMD_SET_SPL_FUSE */ struct mbox_cmd_late_spl_buffer { struct mbox_buffer_header header; diff --git a/src/soc/amd/common/block/psp/rpmc.c b/src/soc/amd/common/block/psp/rpmc.c index 3e5d5e0e7b..a557459854 100644 --- a/src/soc/amd/common/block/psp/rpmc.c +++ b/src/soc/amd/common/block/psp/rpmc.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include <amdblocks/reset.h> #include <bootstate.h> #include <console/console.h> #include <types.h> @@ -136,6 +137,101 @@ static void psp_rpmc_report_status(union psp_rpmc_caps psp_caps, uint32_t hsti_s } } +static bool is_psp_rpmc_slot_available(union psp_rpmc_caps psp_caps) +{ + const enum psp_rpmc_revision rev = get_rpmc_rev(psp_caps); + + switch (rev) { + case PSP_RPMC_REVISION_0: + /* + * psp_rpmc_slot_available doesn't contain the number of available slots, but + * one bit for each slot. When none of those bits is set, there are no usable + * slots any more + */ + return psp_caps.r0.psp_rpmc_slot_available != 0; + case PSP_RPMC_REVISION_1: + return !psp_caps.r1.psp_rpmc_all_slots_used; + default: + return false; + } +} + +static enum cb_err get_first_available_spi_rpmc_counter(union psp_rpmc_caps psp_caps, + uint32_t *rpmc_counter_address) +{ + const enum psp_rpmc_revision rev = get_rpmc_rev(psp_caps); + uint8_t spi_rpmc_available; + unsigned int i; + + switch (rev) { + case PSP_RPMC_REVISION_0: + spi_rpmc_available = psp_caps.r0.spi_rpmc_slots_available; + break; + case PSP_RPMC_REVISION_1: + spi_rpmc_available = psp_caps.r1.spi_rpmc_slots_available; + break; + default: + return CB_ERR; + } + + for (i = 0; i < SPI_RPMC_COUNTER_COUNT; i++) { + if (spi_rpmc_available & BIT(i)) { + *rpmc_counter_address = i; + return CB_SUCCESS; + } + } + + /* No RPMC counter available any more in the SPI flash */ + return CB_ERR; +} + +static void psp_rpmc_provision(union psp_rpmc_caps psp_caps, uint32_t hsti_state) +{ + uint32_t rpmc_counter_addr = 0; + + if (is_hsti_rpmc_provisioned(hsti_state)) + return; + + if (!is_hsti_rpmc_spi_present(hsti_state)) { + printk(BIOS_ERR, "SPI flash doesn't support RPMC\n"); + return; + } + + if (!is_psp_rpmc_slot_available(psp_caps)) { + printk(BIOS_ERR, "No more RPMC provisioning slots available on this SoC\n"); + return; + } + + if (get_first_available_spi_rpmc_counter(psp_caps, &rpmc_counter_addr) != CB_SUCCESS) { + printk(BIOS_ERR, + "No more RPMC conters available for provisioning in the SPI flash\n"); + return; + } + + struct mbox_cmd_set_rpmc_address_buffer buffer = { + .header = { + .size = sizeof(buffer) + }, + .address = rpmc_counter_addr, + }; + + printk(BIOS_DEBUG, "RPMC: perform fusing using RPMC counter address %d\n", + rpmc_counter_addr); + + const int cmd_status = send_psp_command(MBOX_BIOS_CMD_SET_RPMC_ADDRESS, &buffer); + + psp_print_cmd_status(cmd_status, &buffer.header); + + if (cmd_status) { + printk(BIOS_ERR, "RPMC: Fusing request failed\n"); + return; + } + + printk(BIOS_NOTICE, "RPMC: Rebooting\n"); + /* Reboot so that the PSP will do the actual provisioning and fusing */ + warm_reset(); +} + static void psp_rpmc_configuration(void *unused) { union psp_rpmc_caps psp_caps; @@ -148,6 +244,9 @@ static void psp_rpmc_configuration(void *unused) } psp_rpmc_report_status(psp_caps, hsti_state); + + if (CONFIG(PERFORM_RPMC_PROVISIONING)) + psp_rpmc_provision(psp_caps, hsti_state); } BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, psp_rpmc_configuration, NULL); |