Felix Held has submitted this change. ( https://review.coreboot.org/c/coreboot/+/83740?usp=email )
Change subject: soc/amd/common/psp_smi: implement P2C mailbox handling ......................................................................
soc/amd/common/psp_smi: implement P2C mailbox handling
When the PSP wants to access the SPI flash during runtime, but isn't the owner of the SPI flash controller, it sends an SMI to the x86 side. The corresponding SMI handler then checks the P2C (PSP to core) mailbox for the command and data, processes the command, and if needed puts the requested data into the P2C buffer.
The P2C mailbox is a memory region in TSEG aka SMM memory. Both location and size are communicated to the PSP via the PSP SMM info mailbox command which is sent right after mpinit is done.
This commit adds the code to access the P2C mailbox to the PSP SMI handler code, but the handling of the actual mailbox commands the PSP sends to the SMI handler is added in later patches to keep the patch size manageable.
This patch is a heavily reworked version of parts of CB:65523.
Document #55758 Rev. 2.04 was used as a reference.
Test=When selecting SOC_AMD_COMMON_BLOCK_PSP_SMI, Mandolin still builds
Signed-off-by: Felix Held felix-coreboot@felixheld.de Signed-off-by: Ritul Guru ritul.bits@gmail.com Change-Id: I50479bed2332addae652026c6818460eeb6403af Reviewed-on: https://review.coreboot.org/c/coreboot/+/83740 Reviewed-by: Martin Roth martin.roth@amd.corp-partner.google.com Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Matt DeVillier matt.devillier@amd.corp-partner.google.com --- M src/soc/amd/common/block/psp/psp_def.h M src/soc/amd/common/block/psp/psp_smi.c M src/soc/amd/common/block/psp/psp_smm.c 3 files changed, 174 insertions(+), 0 deletions(-)
Approvals: Matt DeVillier: Looks good to me, but someone else must approve Martin Roth: Looks good to me, approved build bot (Jenkins): Verified
diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h index 72569ea..d58aa0b 100644 --- a/src/soc/amd/common/block/psp/psp_def.h +++ b/src/soc/amd/common/block/psp/psp_def.h @@ -111,6 +111,17 @@ #define C2P_BUFFER_MAXSIZE 0xc00 /* Core-to-PSP buffer */ #define P2C_BUFFER_MAXSIZE 0xc00 /* PSP-to-core buffer */
+/* PSP to x86 status */ +enum mbox_p2c_status { + MBOX_PSP_SUCCESS = 0x00, + MBOX_PSP_INVALID_PARAMETER = 0x01, + MBOX_PSP_CRC_ERROR = 0x02, + MBOX_PSP_COMMAND_PROCESS_ERROR = 0x04, + MBOX_PSP_UNSUPPORTED = 0x08, + MBOX_PSP_SPI_BUSY_ASYNC = 0x0a, + MBOX_PSP_SPI_BUSY = 0x0b, +}; + uintptr_t get_psp_mmio_base(void);
void psp_print_cmd_status(int cmd_status, struct mbox_buffer_header *header); @@ -120,4 +131,6 @@
enum cb_err soc_read_c2p38(uint32_t *msg_38_value);
+void enable_psp_smi(void); + #endif /* __AMD_PSP_DEF_H__ */ diff --git a/src/soc/amd/common/block/psp/psp_smi.c b/src/soc/amd/common/block/psp/psp_smi.c index b94366c..e6cc1dc 100644 --- a/src/soc/amd/common/block/psp/psp_smi.c +++ b/src/soc/amd/common/block/psp/psp_smi.c @@ -1,7 +1,167 @@ /* SPDX-License-Identifier: GPL-2.0-only */
#include <amdblocks/psp.h> +#include <amdblocks/smi.h> +#include <console/console.h> +#include <cpu/x86/cache.h> +#include <device/mmio.h> +#include <types.h> +#include "psp_def.h"
+extern struct { + u8 buffer[P2C_BUFFER_MAXSIZE]; +} __aligned(32) p2c_buffer; + +static const uintptr_t p2c_mbox_base = (uintptr_t)&p2c_buffer.buffer; + +#define P2C_MBOX_COMMAND_OFFSET 0x00 +#define P2C_MBOX_STATUS_OFFSET 0x04 +#define P2C_MBOX_BUFFER_OFFSET 0x08 + +union p2c_mbox_status { + struct { + u32 checksum : 8; /* [ 0.. 7] */ + u32 checksum_en : 1; /* [ 8.. 8] */ + u32 reserved : 22; /* [ 9..30] */ + u32 command_ready : 1; /* [31..31] */ + } __packed fields; + u32 raw; +}; + +static u8 rd_bios_mbox_checksum(void) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + return status.fields.checksum; +} + +static void wr_bios_mbox_checksum(u8 checksum) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + status.fields.checksum = checksum; + write32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET, status.raw); +} + +static bool rd_bios_mbox_checksum_en(void) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + return !!status.fields.checksum_en; +} + +static void wr_bios_mbox_ready(bool ready) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + status.fields.command_ready = ready; + write32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET, status.raw); +} + +void enable_psp_smi(void) +{ + wr_bios_mbox_ready(true); +} + +static void disable_psp_smi(void) +{ + wr_bios_mbox_ready(false); +} + +static void clear_psp_command(void) +{ + write32p(p2c_mbox_base + P2C_MBOX_COMMAND_OFFSET, 0); +} + +static u32 get_psp_command(void) +{ + return read32p(p2c_mbox_base + P2C_MBOX_COMMAND_OFFSET); +} + +static struct mbox_default_buffer *get_psp_command_buffer(void) +{ + return (struct mbox_default_buffer *)(p2c_mbox_base + P2C_MBOX_BUFFER_OFFSET); +} + +static uint32_t get_psp_cmd_buffer_length(void) +{ + return read32(&get_psp_command_buffer()->header.size); +} + +static u8 calc_psp_buffer_checksum8(void) +{ + const uint8_t *data = (const u8 *)get_psp_command_buffer(); + const size_t size = get_psp_cmd_buffer_length(); + u8 checksum = 0; + size_t i; + + for (i = 0; i < size; i++) + checksum += read8(data + i); + + return checksum; +} + +static void write_psp_cmd_buffer_status(enum mbox_p2c_status status) +{ + return write32(&get_psp_command_buffer()->header.status, status); +} + +static enum mbox_p2c_status check_psp_command(void) +{ + if (rd_bios_mbox_checksum_en() && + calc_psp_buffer_checksum8() != rd_bios_mbox_checksum()) + return MBOX_PSP_CRC_ERROR; + + if (get_psp_cmd_buffer_length() > P2C_BUFFER_MAXSIZE - P2C_MBOX_BUFFER_OFFSET) + return MBOX_PSP_INVALID_PARAMETER; + + return MBOX_PSP_SUCCESS; +} + +static void handle_psp_command(void) +{ + enum mbox_p2c_status status; + u32 cmd; + + status = check_psp_command(); + if (status != MBOX_PSP_SUCCESS) + goto out; + + cmd = get_psp_command(); + + switch (cmd) { + default: + printk(BIOS_ERR, "PSP: Unknown command %d\n", cmd); + status = MBOX_PSP_UNSUPPORTED; + break; + } + +out: + write_psp_cmd_buffer_status(status); + + if (status == MBOX_PSP_SUCCESS && rd_bios_mbox_checksum_en()) + wr_bios_mbox_checksum(calc_psp_buffer_checksum8()); +} + +/* TODO: check if all wbinvd() calls are necessary */ void psp_smi_handler(void) { + disable_psp_smi(); + + wbinvd(); + + handle_psp_command(); + + wbinvd(); + + clear_psp_command(); + enable_psp_smi(); + + wbinvd(); + + reset_psp_smi(); } diff --git a/src/soc/amd/common/block/psp/psp_smm.c b/src/soc/amd/common/block/psp/psp_smm.c index 4f76ebc..00e00dd 100644 --- a/src/soc/amd/common/block/psp/psp_smm.c +++ b/src/soc/amd/common/block/psp/psp_smm.c @@ -92,6 +92,7 @@
if (CONFIG(SOC_AMD_COMMON_BLOCK_PSP_SMI)) { configure_psp_smi(); + enable_psp_smi(); }
printk(BIOS_DEBUG, "PSP: Notify SMM info... ");