soc/amd/common/block/psp: Add BIOS SPI flash semaphore

When coreboot is operating on the SPI flash lock the bus by
setting SPI_SEMAPHORE_BIOS_LOCKED in SPI_MISC_CNTRL. This prevents
SMM from accidentally corrupting SPI CTRL registers, even though
SMM backups and restores SPI CTRL registers.

TEST: Booted an AMD glinda and observed SMM not accessing the SPI
      controller as long as ring 0 is operating on it.

Signed-off-by: Patrick Rudolph <patrick.rudolph@amd.com>
Change-Id: Iaeda356b55d3f203c75f4056da7bde2abacebc41
Reviewed-on: https://review.coreboot.org/c/coreboot/+/88438
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Matt DeVillier <matt.devillier@gmail.com>
This commit is contained in:
Patrick Rudolph 2025-07-15 12:11:28 +02:00 committed by Matt DeVillier
commit a17a41559a
3 changed files with 50 additions and 1 deletions

View file

@ -89,6 +89,7 @@ enum spi100_speed {
/* AMD has re-purposed this unused SPI controller register bit as a semaphore to synchronize
access to the SPI controller between SMM and non-SMM software/OS driver. */
#define SPI_SEMAPHORE_DRIVER_LOCKED BIT(4)
#define SPI_SEMAPHORE_BIOS_LOCKED BIT(3)
struct spi_config {
/*

View file

@ -94,7 +94,14 @@ static enum mbox_p2c_status find_psp_spi_flash_device_region(uint64_t target_nv_
static bool spi_controller_busy(void)
{
bool busy = false;
bool busy;
/* When the firmware is using the SPI controller stop here */
busy = (spi_read8(SPI_MISC_CNTRL) & SPI_SEMAPHORE_BIOS_LOCKED);
if (busy) {
printk(BIOS_NOTICE, "PSP: SPI controller blocked by coreboot (ring 0)\n");
return true;
}
/*
* When ring0 is operating on the SPI flash and the controller is

View file

@ -4,6 +4,7 @@
#include <spi_flash.h>
#include <soc/pci_devs.h>
#include <amdblocks/lpc.h>
#include <amdblocks/smi.h>
#include <amdblocks/spi.h>
#include <device/pci_ops.h>
#include <lib.h>
@ -122,6 +123,10 @@ static uint8_t fifo[SPI_FIFO_DEPTH];
void fch_spi_backup_registers(void)
{
/* When bus is locked no need for backup */
if (ENV_SMM && (spi_read8(SPI_MISC_CNTRL) & SPI_SEMAPHORE_BIOS_LOCKED))
return;
cmd_code = spi_read8(SPI_CMD_CODE);
tx_byte_count = spi_read8(SPI_TX_BYTE_COUNT);
rx_byte_count = spi_read8(SPI_RX_BYTE_COUNT);
@ -132,6 +137,10 @@ void fch_spi_backup_registers(void)
void fch_spi_restore_registers(void)
{
/* When bus is locked no need for backup */
if (ENV_SMM && (spi_read8(SPI_MISC_CNTRL) & SPI_SEMAPHORE_BIOS_LOCKED))
return;
spi_write8(SPI_CMD_CODE, cmd_code);
spi_write8(SPI_TX_BYTE_COUNT, tx_byte_count);
spi_write8(SPI_RX_BYTE_COUNT, rx_byte_count);
@ -308,7 +317,39 @@ static int fch_spi_flash_protect(const struct spi_flash *flash, const struct reg
return 0;
}
/* Block PSP SMI while operating on the SPI flash */
static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
{
uint8_t reg8;
if (CONFIG(SOC_AMD_COMMON_BLOCK_PSP_SMI)) {
if (ENV_RAMSTAGE || ENV_SMM) {
reg8 = spi_read8(SPI_MISC_CNTRL);
if (reg8 & SPI_SEMAPHORE_BIOS_LOCKED)
return -1;
}
if (ENV_RAMSTAGE)
spi_write8(SPI_MISC_CNTRL, reg8 | SPI_SEMAPHORE_BIOS_LOCKED);
}
return 0;
}
/* Allow PSP SMI when not operating on the SPI flash */
static void spi_ctrlr_release_bus(const struct spi_slave *slave)
{
uint8_t reg8;
if (ENV_RAMSTAGE && CONFIG(SOC_AMD_COMMON_BLOCK_PSP_SMI)) {
reg8 = spi_read8(SPI_MISC_CNTRL);
spi_write8(SPI_MISC_CNTRL, reg8 & ~SPI_SEMAPHORE_BIOS_LOCKED);
}
}
static const struct spi_ctrlr fch_spi_flash_ctrlr = {
.claim_bus = spi_ctrlr_claim_bus,
.release_bus = spi_ctrlr_release_bus,
.xfer_vector = xfer_vectors,
.max_xfer_size = SPI_FIFO_DEPTH,
.flags = SPI_CNTRLR_DEDUCT_CMD_LEN | SPI_CNTRLR_DEDUCT_OPCODE_LEN,