Felix Held has submitted this change. ( https://review.coreboot.org/c/coreboot/+/84707?usp=email )
Change subject: soc/amd/common/psp: add RPMC provisioning code ......................................................................
soc/amd/common/psp: add RPMC provisioning code
Add the code to request the provisioning of the RPMC root key from the PSP. When RPMC hasn't already been provisioned enabled and the PSP has detected a SPI flash chip that both supports RPMC and has monotonic counters that can still be provisioned, we send the PSP mailbox command to request the RPMC provisioning and then reset the system, so the PSP can do the actual provisioning.
TEST=On an out of tree AMD reference board using the Cezanne SoC code, provisioning RPMC works as expected when selecting the corresponding PERFORM_RPMC_PROVISIONING Kconfig option:
1st boot to initiate the RPMC provisioning:
[DEBUG] PSP: Querying PSP capabilities...OK [DEBUG] PSP: Querying HSTI state...OK [SPEW ] RPMC isn't provisioned [SPEW ] SPI flash supports RPMC [SPEW ] RPMC revision 0 [SPEW ] PSP NVRAM isn't healthy [SPEW ] PSP NVRAM is using RPMC protection [SPEW ] SPI flash RPMC counter 0 can still be provisioned [SPEW ] SPI flash RPMC counter 1 can still be provisioned [SPEW ] SPI flash RPMC counter 2 can still be provisioned [SPEW ] SPI flash RPMC counter 3 can still be provisioned [SPEW ] SPI flash RPMC counter 0 is in use [SPEW ] SPI flash RPMC counter 1 is not in use [SPEW ] SPI flash RPMC counter 2 is not in use [SPEW ] SPI flash RPMC counter 3 is not in use [SPEW ] SoC RPMC slot 0 can still be provisioned [SPEW ] SoC RPMC slot 1 can still be provisioned [SPEW ] SoC RPMC slot 2 can still be provisioned [SPEW ] SoC RPMC slot 3 can still be provisioned [DEBUG] RPMC: perform fusing using RPMC counter address 0 [DEBUG] OK [NOTE ] RPMC: Rebooting [INFO ] warm_reset() called!
2nd boot after the provisioning is done:
[DEBUG] PSP: Querying PSP capabilities...OK [DEBUG] PSP: Querying HSTI state...OK [SPEW ] RPMC is provisioned [SPEW ] SPI flash supports RPMC [SPEW ] RPMC revision 0 [SPEW ] PSP NVRAM isn't healthy [SPEW ] PSP NVRAM is using RPMC protection [SPEW ] SPI flash RPMC counter 0 has already been provisioned [SPEW ] SPI flash RPMC counter 1 can still be provisioned [SPEW ] SPI flash RPMC counter 2 can still be provisioned [SPEW ] SPI flash RPMC counter 3 can still be provisioned [SPEW ] SPI flash RPMC counter 0 is in use [SPEW ] SPI flash RPMC counter 1 is not in use [SPEW ] SPI flash RPMC counter 2 is not in use [SPEW ] SPI flash RPMC counter 3 is not in use [SPEW ] SoC RPMC slot 0 has already been provisioned [SPEW ] SoC RPMC slot 1 can still be provisioned [SPEW ] SoC RPMC slot 2 can still be provisioned [SPEW ] SoC RPMC slot 3 can still be provisioned
Signed-off-by: Felix Held felix-coreboot@felixheld.de Change-Id: Ia7760c0bf7618ca60ef160329d0110ac8109032a Reviewed-on: https://review.coreboot.org/c/coreboot/+/84707 Reviewed-by: Marshall Dawson marshalldawson3rd@gmail.com Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/soc/amd/common/block/psp/Kconfig M src/soc/amd/common/block/psp/psp_def.h M src/soc/amd/common/block/psp/rpmc.c 3 files changed, 115 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Marshall Dawson: Looks good to me, approved
diff --git a/src/soc/amd/common/block/psp/Kconfig b/src/soc/amd/common/block/psp/Kconfig index 9262e47..3ae5e43 100644 --- a/src/soc/amd/common/block/psp/Kconfig +++ b/src/soc/amd/common/block/psp/Kconfig @@ -38,6 +38,15 @@ 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 d1f57ac..d11199d 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 @@ 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 3e5d5e0..a557459 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 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 @@ }
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);