diff options
author | Felix Held <felix-coreboot@felixheld.de> | 2024-09-13 19:35:10 +0200 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2024-10-28 21:17:48 +0000 |
commit | d5764b8a5ae54204355d11d557d127c41352ffa4 (patch) | |
tree | 8b2b446fef4849035faa33af0ae6503e47fae6e3 /src/soc/amd/common/block | |
parent | c914e747e7beb6f813ce93c34ca9e0c9467aa5a1 (diff) |
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>
Diffstat (limited to 'src/soc/amd/common/block')
-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); |